关于spring data jpa一级缓存的问题
作者:TheNether
spring data jpa一级缓存
jpa更新数据,数据库更新了,但是查询出来的还是更新前的问题,这是因为jpa的一级缓存,查询默认是从缓存中查询的,而不是从DB查询。
解决办法
repository
update方法上加入@Modifying(clearAutomatically = true)即可,它更新完数据库后会主动清理一级缓存,但我用了好像没什么效果,可能使用方法不对,建议使用下面这个
entityManager对象
通过 em.clear(); 在每次查询前清除 JPA 缓存
spring data jpa的那些坑
springdatajpa是持久化框架,底层是hibernate实现的,基本原理与hibernate一致。
hibernate缓存机制
Hibernate的一级缓存就是指Session缓存,此Session非http的session会话技术,可以理解为JDBC的Connection,连接会话,Session缓存就是一块内存空间,用来存放相互管理的java对象,在使用Hibernate查询对象的时候,首先使用对象的OID(ObjectID)
在Hibernate的一级缓存空间进行查找,如果通过OID匹配到了对象,就直接从一级缓存中取出使用,如果没有找到匹配该OID值的对象,这才会进行查询数据库。
当从数据库中查询数据的时候,该数据就会被放入到Session缓存中,目的就是为了减少数据库的访问次数,从而提高性能
特点
- 当应用程序调用Session接口的 save(), update(), saveOrUpdate() 时候,如果缓存中没 有相应的对象,Hb就会自动的把查询信息加入到缓存。
- 当应用程序调用Session接口的 load(), get(), list() 等查询方法的时候,会进行判断缓存中是否有数据,同摘要。
- 当应用程序调用Session接口的 close() Session缓存会被清空
案例
public void demo1 (){ Session session = HibernateUtils.openSession(); Transaction transaction = session.beginTransaction(); User user1 = session.get(User.class, "1"); System.out.println(user1); System.out.println("-------------"); User user2 = session.get(User.class, "1"); System.out.println(user2); System.out.println(user1 == user2); transaction.commit(); session.close(); }
我们发现第一次执行Session的get()方法的时候,由于一级缓存中没有数据,所以会向数据库发送一条sql语句进行查询,第二次调用get()的时候,则不会发送sql语句,而是从一级缓存中取的,所以user和user2的内存地址相等
一级缓存的快照区
Hibernate向一级缓存放入数据的时候,同时复制一份放到Hibernate快照中,当使用commot()提交事务的时候,同时会清理Session的一级缓存,这是会用OID判断一级缓存中的对象和快照中的对象是否一致,如果一致则执行update 语句,将缓存中的内容同步到数据库,并且更新快照,这也就实现了不使用 update 语句就可以自动更新数据库,Hibernate快照的作用也就是为了保持缓存中的数据和数据库中的数据的一致性。
线上坑案例
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。