spring data jpa 遇到的坑

更新了你不想更新的实例

首先findOne()方法找到一个实体,暂且叫A,实体包含Id属性和一个引用类型的数据
然后new一个这个实体,叫B,将那个引用类型稍作修改后set到B中
save()这个实体B

理想情况是B作为一个新的记录被插入到数据库,这个没问题,但是A在这次save()中那个引用类型也被保存了,问题是并没有save()实体A

实际上,这是由于查出来的实体是一个有entityManager管理的托管状态的一个实体,他的属性在变化后hibernate是知道的,在默认情况下调用了save()等方法后,由于事务的提交,一并将A的改变提交了

解决办法可以通过entityManager的clear()方法,来将托管状态的实体清除,接下来的事务提交不会提交被清除的实体,如果使用的是CURDRepositry或JPARepositry等,可以通过一下办法调用entitymanager

他会清除当前session所保存的实体

在同一个方法内(或者说是同一个session内),期望多次通过findOne来拿到最新的实体,但发现只有第一次会发送sql语句,后来的只会从一级缓存拿

与上面的类似,可以通过在findOne之后clear()来解决问题,因为hibernate会先去一级缓存中找实体,如果没有,就在数据库中找,所以当你的代码第一次查时会放到一级缓存中,导致后续的查找都从一级缓存中查

(这个方法暂时有问题)还有另一种方式就是不要写那么多findOne(),找到一次后,使用entityManager的refresh()方法来刷新这个实体,可以达到一样的效果(好像发出了sql,但是没有更新实体)

springboot中,如果同时使用JPA或flyway可能会遇到的问题

如果开启了jpa,并且application.properties中配置了如下语句

1
2
#jpa自动根据实体类更新表结构
spring.jpa.hibernate.ddl-auto=update

并且又配置了flyway
那么
springboot启动的时候,会先跑flyway,后跑JPA