jpa中由于缓存问题引起的,查询出的数据不是数据库中最新数据
在某一方法中对A对象进行修改操作,且在这个方法返回之前对A对象进行查询。发现得到的数据是A对象修改之前的数据,而并非A对象修改之后的数据。这是什么原因造成的呢?答:缓存问题。为什么说是缓存问题呢?都知道JPA的底层实现是Hibernate,也可以说JPA是Hibernate的升级版本。Hibernate的缓存机制分为:一级缓存和二级缓存。一级缓存:hibernate默认开启一级缓存,仅当commi
在某一方法中对A对象进行修改操作,且在这个方法返回之前对A对象进行查询。发现得到的数据是A对象修改之前的数据,而并非A对象修改之后的数据。这是什么原因造成的呢?
答:缓存问题。
为什么说是缓存问题呢?
都知道JPA的底层实现是Hibernate,也可以说JPA是Hibernate的升级版本。
Hibernate的缓存机制分为:一级缓存和二级缓存。
一级缓存:hibernate默认开启一级缓存,仅当commit或者flush时会根据快照机制确定是否更新到数据库。(快照机制:数据操作时,不仅会把数据放入一级缓存区,还会把相同的数据放入快照区。在此期间,若数据变更,缓存区的数据也会发生变化。当commit或者flush时,会对比缓存区和快照区的数据是否一致,如果一致(数据无变化)不进行操作,若不一致(缓存区的数据发生了变化)则调用update方法,更新数据到数据库。)
二级缓存:二级缓存默认是关闭的,多用于存放频繁查询,且变更机率较小的数据。相同数据查询时,直接从缓存中取,而不再访问数据库。减轻了数据库的压力。
默认查询时会先去一级缓存中取数据,取不到数据会去二级缓存中取(配置了二级缓存),如果还是没有取到数据,则访问数据库。
Repository中方法都加了事务,默认@Transactional(readOnly = true)只读。
查询操作时无影响,进行修改和删除操作时需要添加@Modifying和@Transactional
@Modifying标识该操作是修改操作
@Transactional声明事务性操作,Transactional(readOnly = false)可进行修改操作
不加@Modifying会出现以下问题:
org.hibernate.hql.QueryExecutionRequestException: Not supported for DML operations
不加@Transactional会出现以下情况:
org.springframework.dao.InvalidDataAccessApiUsageException: Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query
使用时你可能会发现,对某一数据进行update操作后查询该数据,得到的是update之前的数据,而不是最新的数据。这是缓存造成的。
解决办法:
1.设置@Modifying(clearAutomatically=true) 会刷新一级缓存,得到最新的数据。
注意:clear后会把最新的数据刷新到一级缓存中,但不会flush,如果此时调用save()方法(刷新缓存)但不会把最新数据更新到数据库,在此期间(未flush)调用@Modifying(clearAutomatically=true)方法操作的数据可能就不是正确的,因此必须使用saveAndFlush(),或者设置flushAutomatically = true
设置如下:会在执行修改操作之前flush数据,从而拿到最新的数据。
@Modifying(clearAutomatically = true, flushAutomatically = true)
2.另外一种清缓存的办法:引入EntityManager,在获取最新数据之前进行clear
@Autowired
private EntityManager entityManager;
entityManager.unwrap(Session.class).clear();
更多推荐
所有评论(0)