JPA遇上Lombook的大坑—@Version乐观锁不起作用
2019-11-05更新
最新发现,不是Lombook的锅,但是Lombook也跑不掉责任
以下常见做法:
- 如果使用了Lombook,就会用Lombook的注解,而不是显式的写出getter和setter方法;因为没有getter和setter方法,jpa的其他注解比如@Column就会加在属性上;
- 一般项目都有个BaseEntity,里面放了id等公共属性;BaseEntity一般不会用Lombook,公共属性的注解加在了getter方法上,比较符合java面向对象的封装性(让jpa通过get方法访问属性,而不是直接访问私有属性);
注解不起作用的真正原因:
BaseEntity的注解放在哪里,子类的注解也必须放在那里,否则失效(即统一放在属性上,或统一放在getter方法上)。更进一步,如果将BaseEntity的注解同时放在属性上和get方法上,相当于值在get方法上设置注解。
参考:
- https://segmentfault.com/q/1010000010910022/a-1020000010920576
- https://www.cnblogs.com/sxdcgaq8080/p/7884477.html
- https://blog.csdn.net/gaohe7091/article/details/63253386
某业务需要使用到乐观锁,加了一个version
字段,一般使用MyBatis就用sql语句自己去维护version了,但是项目使用的是Spring Data JPA,写hql语句不是很方便,所以用了@Version
注解。
@Version
注解在你使用jpa的save()、savaAll()等方法时,会自动对version这个字段作为乐观锁执行必要的操作,失败则会抛出乐观锁异常ObjectOptimisticLockingFailureException
挺方便的;但是对于使用@Query
注解自己写hql语句的方法并不生效,需要像使用MyBatis那样自己去写,例如:
@Modify
@Query("update ClassName beanName set beanName.aaa = :newAaa, beanName.version = beanName.version+1 where beanName.version = :version")
int updateClassName(@Param("newAaa") String newAaa, @Param("version") Long version)
其中ClassName和beanName分别代表要修改的实体类名称和对象名称。需要自己在hql语句中判断version有没有被改动以及version加1。返回值如果是0,代表修改不成功;需要自己去判断是否为0,然后为0则抛出乐观锁的异常。
本以为加个注解多简单的事,竟然不起作用?jpa配置改为show_sql: true
,即在控制台显示hql语句,发现自动生成的hql语句里没有where version=?
的判断条件。说明@Version
注解被没有被识别到。
各种去搜@version
注解的正确用法,发现并没有什么特殊配置需求;以及搜索@Version注解不起作用,只能搜到一个回答
引进的类错误
import org.springframework.data.annotation.Version
改为import javax.persistence.Version
明显不是我遇到的问题。
自己新建了一个工程去测试,发现没有任何问题,@version
注解是起作用的。想想两个工程的区别,是因为项目使用了Lombook?
一通测试,结果如下:
- 使用Lombook的@Data注解,自动生成getter和setter方法,@Version注解加在version变量上,不生效;
- 使用Lombook的@Data注解,手动加上version字段的getter和setter方法,@Version注解加在version变量上,不生效;
- 使用Lombook的@Data注解,手动加上version字段的getter和setter方法,@Version注解加在version的getter方法上,生效;
- 不使用Lombook的@Data注解,手动生成getter和setter方法,@Version注解加在version变量上和加在version的getter方法上,都生效。
就是Lombook的锅。
就是Lombook的锅。
就是Lombook的锅。
为什么呢?