解决:jpa中由于缓存问题引起的,查询出的数据不是数据库中最新数据

在某一方法中对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之前的数据,而不是最新的数据。这是缓存造成的。

解决办法:设置@Modifying(clearAutomatically=true) 会刷新一级缓存,得到最新的数据。
注意:clear后会把最新的数据刷新到一级缓存中,但不会flush,如果此时调用save()方法(刷新缓存)但不会把最新数据更新到数据库,在此期间(未flush)调用@Modifying(clearAutomatically=true)方法操作的数据可能就不是正确的,因此必须使用saveAndFlush(),或者设置flushAutomatically = true

设置如下:会在执行修改操作之前flush数据,从而拿到最新的数据。

@Modifying(clearAutomatically = true, flushAutomatically = true) 
另外一种清缓存的办法:引入EntityManager,在获取最新数据之前进行clear
 @Autowired
    private EntityManager entityManager;
entityManager.unwrap(Session.class).clear();
  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值