Spring Data JPA learning summary

When using spring-cloud 2.0.3, add the spring-boot-start-data-jpa dependency and configure it, and then test:

This is the service method, which injects the IUserInfoDao interface (inheriting JpaRepository<UserInfoModel, Integer>);

    @Override
    public UserInfoModel getById(Integer id) {
        return userInfoDao.getOne(id);
    }

This is the test method, injecting the IUserInfoService interface;

In the test, the getOne() method is used first, and the object information can be obtained only by querying.

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

However, when testing the editing (update) object, an exception was exposed when executing the test: org.hibernate.LazyInitializationException: could not initialize proxy - no Session exception; 

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

The exception information is as follows:

I checked a lot of information and said that adding @Transactional to the method can solve the problem of lazy loading, but when testing the update in JUnit, you need to query first, and then set the data to update, but @Transactional will roll back, making the data update invalid

    /**
     * 测试修改用户信息
     */
    @Test
    @Transactional
    public void updateUserInfo(){
        UserInfoModel oldUser = userInfoService.getById(1);
        oldUser.setUserAddress("中国陕西");
        UserInfoModel updateResult = userInfoService.update(oldUser);
        System.err.println("email : " + updateResult.getUserEmail());
    }

Looking at the printed information, the update is successful, but the database has not changed.

Look carefully at the following message, Rolled back... 

All the information in red is as follows:

Later, I checked the api and found that the getOne() method returns a proxy object (a reference) of the entity object. The source code is as follows:

    /**
	 * 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);

There is a findById() method in the CrudRepository<T, ID> interface. The source code is as follows:

    /**
	 * 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);

The return value of this method is an Optional<T>. There is a get() method in the Optional class, which returns the current object/value. The source code is as follows:

    /**
     * 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;
    }

By looking at the source code and api, it is found that you can use findById(), first call findById() to return the encapsulated object, and then use the get() method to return the entity object.

Remove the @Transactional annotation on the update() method and replace getOne() with 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();
    }

During the editing test, the database information was updated successfully.

There is a findOne() method in the QueryByExampleExecutor<T> interface. The source code is as follows:

    /**
	 * 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);

 For this Example<S>, it is actually an encapsulated instance of a query condition. For example, to query UserInfo information (userNameCn="xxx"), an object of Example<UserInfoModel> is created through the Example.of(userInfo) method, and then Call the findOne() method;

     @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;
    }

The findOne() method will return an Optional<T> object, and there are many built-in methods in the Optional class. The isPresen() method returns the result of whether the Optional object is null. If the current Optional object has a value, it returns true, otherwise it returns false, when the result has a value, and then call its get() method, it will return an object of type <T>, that is, the instance result we want to query.

The source code of isPresent() is as follows:

    /**
     * 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;
    }

The source code of get() is as follows:

    /**
     * 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;
    }

 

{{o.name}}
{{m.name}}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324109252&siteId=291194637