zoukankan      html  css  js  c++  java
  • jpa2.x的getOne()/findOne()/findById()的区别及使用

    使用spring-cloud 2.0.3时,加入了spring-boot-start-data-jpa依赖之后并配置完成,然后进行测试:

    这是service 方法,注入了IUserInfoDao接口(继承JpaRepository<UserInfoModel, Integer>);

        @Override
        public UserInfoModel getById(Integer id) {
            return userInfoDao.getOne(id);
        }
    这是测试方法,注入IUserInfoService接口;

    在测试中先使用的是getOne() 的方法,仅做查询可以得到对象信息,

        /**
         * 测试查询指定用户信息
         */
        @Test
        public void getById(){
            UserInfoModel getResult = userInfoService.getById(1);
            System.err.println("id : " + getResult.getUserId());
        }


    但是在测试编辑(update)对象时,执行测试时曝出异常:org.hibernate.LazyInitializationException: could not initialize proxy - no Session的异常;

        @Test
        public void updateUserInfo(){
            UserInfoModel oldUser = userInfoService.getById(1);
            oldUser.setUserAddress("中国陕西");
            UserInfoModel updateResult = userInfoService.update(oldUser);
            System.err.println("email : " + updateResult.getUserEmail());
        }
    异常信息如下:



    查了好多资料说,在方法上加入@Transactional可以解决问题懒加载的问题,但是在JUnit测试update时,需要先查询,在设置数据进行更新,然而@Transactional会回滚,导致数据更新无效

        /**
         * 测试修改用户信息
         */
        @Test
        @Transactional
        public void updateUserInfo(){
            UserInfoModel oldUser = userInfoService.getById(1);
            oldUser.setUserAddress("中国陕西");
            UserInfoModel updateResult = userInfoService.update(oldUser);
            System.err.println("email : " + updateResult.getUserEmail());
        }
    看打印的信息,是更新成功了,但是数据库并没有变



    仔细看下面有一条信息,Rolled back ...



    红色部分全部信息如下:



    后来查看api 发现getOne()方法返回的是实体对象的代理对象(a reference),源码如下:

        /**
         * Returns a reference to the entity with the given identifier.
         *
         * @param id must not be {@literal null}.
         * @return a reference to the entity with the given identifier.
         * @see EntityManager#getReference(Class, Object)
         * @throws javax.persistence.EntityNotFoundException if no entity exists for given {@code id}.
         */
        T getOne(ID id);
    在CrudRepository<T, ID>接口中有一个findById()的方法 ,源码如下:

        /**
         * Retrieves an entity by its id.
         *
         * @param id must not be {@literal null}.
         * @return the entity with the given id or {@literal Optional#empty()} if none found
         * @throws IllegalArgumentException if {@code id} is {@literal null}.
         */
        Optional<T> findById(ID id);
    该方法的返回值是一个Optional<T>,在Optional类中有个get()方法,返回的是当前对象/值,源码如下:

        /**
         * If a value is present in this {@code Optional}, returns the value,
         * otherwise throws {@code NoSuchElementException}.
         *
         * @return the non-null value held by this {@code Optional}
         * @throws NoSuchElementException if there is no value present
         *
         * @see Optional#isPresent()
         */
        public T get() {
            if (value == null) {
                throw new NoSuchElementException("No value present");
            }
            return value;
        }
    通过看源码和api,发现可以使用findById(),先调用findById()返回封装后的对象,然后使用get()方法,返回实体对象。

    去掉update()方法上的@Transactional注解,将getOne()换成findById()

        @Override
        public UserInfoModel getById(Integer id) {
            //使用getOne()返回的是代理对象,无法直接操作,会出现hibernate lazyxxx  no session 的错误
            //在测试方法上加入@Transactional注解可以解决报错的问题
    //        return userInfoDao.getOne(id);
            Optional<UserInfoModel> findResult = userInfoDao.findById(id);
            return findResult.get();
        }
    在进行编辑测试,数据库信息更新成功。





    在QueryByExampleExecutor<T>接口中有一个findOne()方法,源码如下:

        /**
         * Returns a single entity matching the given {@link Example} or {@literal null} if none was found.
         *
         * @param example must not be {@literal null}.
         * @return a single entity matching the given {@link Example} or {@link Optional#empty()} if none was found.
         * @throws org.springframework.dao.IncorrectResultSizeDataAccessException if the Example yields more than one result.
         */
        <S extends T> Optional<S> findOne(Example<S> example);
     对于这个Example<S>,其实是一个查询条件的封装实例,比如要条件查询UserInfo的信息(userNameCn="xxx"),则通过Example.of(userInfo)方法创建Example<UserInfoModel> 的一个对象,然后调用findOne()方法;

         @Override
        public UserInfoModel findOne(UserInfoModel userInfo) {
            //Example对象可以当做查询条件处理,将查询条件得参数对应的属性进行设置即可
            //可以通过ExampleMatcher.matching()方法进行进一步得处理
            Example<UserInfoModel> userExample = Example.of(userInfo);
            Optional<UserInfoModel> exampleResult = userInfoDao.findOne(userExample);
            //需要结果过做判断,查询结果为null时会报NoSuchElementException
            if (exampleResult.isPresent()) {
                return exampleResult.get();
            }
            return null;
        }
    findOne()方法会返回一个Optional<T>对象,再Optional类中有很多内置的方法,其中isPresen()方法返回Optional对象是否为null的结果,如果当前Optional对象有值,则返回true,否则返回false,当结果有值时,然后调用它的get()方法,会返回一个<T>类型的对象,即我们要查询的实例结果。

    isPresent()源码如下:

        /**
         * Return {@code true} if there is a value present, otherwise {@code false}.
         *
         * @return {@code true} if there is a value present, otherwise {@code false}
         */
        public boolean isPresent() {
            return value != null;
        }
    get()源码如下:

        /**
         * If a value is present in this {@code Optional}, returns the value,
         * otherwise throws {@code NoSuchElementException}.
         *
         * @return the non-null value held by this {@code Optional}
         * @throws NoSuchElementException if there is no value present
         *
         * @see Optional#isPresent()
         */
        public T get() {
            if (value == null) {
                throw new NoSuchElementException("No value present");
            }
            return value;
        }

  • 相关阅读:
    python读写hdf5及cdf格式文件
    常用python shell
    opencv的使用——经典大坑
    opencv python实用操作
    opencv python基本操作
    opencv c++实用操作
    opencv c++基本操作
    opencv安装
    [HNOI2005]星际贸易
    [2017SEERC]Divide and Conquer
  • 原文地址:https://www.cnblogs.com/zhuyeshen/p/12661237.html
Copyright © 2011-2022 走看看