解决JPA对查询对象set属性值导致数据更新的问题

问题描述

1、开启了数据库事务

2、通过EntityManager执行查询,获得返回对象

3、代码业务逻辑处理,其中有对象set属性值的操作

4、没有执行过JPA的save方法或者update语句

5、提交数据库事务,发现数据库中对应的数据更新成了新的属性值

问题复现

 

@Transactional
@Override
public void selectAndFlush(String id) {
   User user = crudDao.selectByPrimaryKey(id);
   user.setName("testFlushNotUpdateDB");
}

 

Hibernate: selectuser0_.AGE as AGE8_0_, user0_.CARD as CARD9_0_, user0_.NAME as NAME10_0_, user0_.PRICE as PRICE11_0_ from USER user0_ where user0_.ID=?

Hibernate: update USER set AGE=?, CARD=?, NAME=?, PRICE=? where ID=?

可以看到在set方法之后JPA自动帮我们执行了update操作

问题原因

根本原因是因为我们在执行查询以后,查询结果对象在EntityManager上下文中进行了一级缓存,执行set方法以后缓存对象状态【持久态】,事务提交时会自动帮我们flush到数据库中,导致数据被更新,下图为一级缓存对象:

解决JPA对查询对象set属性值导致数据更新的问题

 

 解决方法

这里提供4中解决方法:

1、提交事务之前执行EntityManager.clear()方法,清理缓存对象

2、业务代码在不需要更新数据时避免直接对查询对象进行set操作,可以使用BeanUtils.copyProperties()方法复制对象,再进行set操作

3、使用EntityManager.evict()方法清理指定对象

4、修改JPA的FlushMode,没有测试过,理论可行,代码如下:

 

((Session) getEntityManager().getDelegate()).setFlushMode(FlushMode.MANUAL);

 

上一篇:SpringBoot+JPA完成博客分类相关功能


下一篇:Spring Boot入门系列(二十六)超级简单!Spring Data JPA 的使用!