接入ping++支付,账户余额的数据安全问题,使用jpa乐观锁+AOP重试机制
乐观锁:<span style="white-space:pre"></span>model实体类加version字段
<span style="white-space:pre"></span>private Integer version=0; //jpa乐观锁@Version@Column(name = "version")public Integer getVersion() {return version;}public void setVersion(Integer version) {this.version = version;}
---修改实体时,
<span style="white-space:pre"></span>tradeBAccount.setVersion(tradeBAccount.getVersion()+1);//乐观锁<span style="white-space:pre"></span>tradeBAccountDao.save(tradeBAccount);
参考:
并发锁事务重试机制(JPA高并发下的乐观锁异常)
我的博文中,有一篇短文Java结合Junit做并发测试用例,是介绍JPA在高并发下,多个Service方法更新
同一个记录;在异常信息中有StaleObjectStateException和ObjectOptimisticLockingFailureException异常信
息。有些业务这种靠JPA维护的版本信息是可行的,如果两个不同用户同事(高并发)购买一件马丁靴鞋子,最后会更新该马丁靴在库数量,如果没有重试机制,肯定只有一个用户购买失败;可能这没有什么,用户再次提交购买就ok了;可是作为事逼可能成就人生的工程师,你一定不能容忍,于是有了重试机制。
1:解决方案
定义Aspectj拦截器,指定方法发生乐观锁异常时,进行重试。
2:show coding.
(1) 因为不是所有方法发生乐观锁异常都是需要重试机制的,所以需要先定义切面接口定义IsTryAgain
- /**
- * 自定义尝试切面接口
- */
- @Retention(RetentionPolicy.RUNTIME)
- public @interface IsTryAgain {
- // marker annotation
- }
(2)Service接口方法加上切面接口定义
- /**
- * 并发乐观锁需要重试的方法
- */
- @IsTryAgain
- boolean TryAgainMethod() throws Exception;
(3)定义Aspectj切面拦截器
定义重试切面方法,是为了发生乐观锁异常时在一个全新的事务里提交上一次的操作,直到达到重试上限;因此切面实现 org.springframework.core.Ordered 接口,这样我们就可以把切面的优先级设定为高于事务通知 。
- @Aspect
- public class SystemArchitecture {
- @Pointcut("execution(* myapp..service..*(..))")
- public void businessService() {
- }
- }
- @Aspect
- class ConcurrentOperationExecutor implements Ordered {
- private static final int DEFAULT_MAX_RETRIES = 2;
- private int maxRetries = DEFAULT_MAX_RETRIES;
- private int order = 1;
- public void setMaxRetries(int maxRetries) {
- this.maxRetries = maxRetries;
- }
- public int getOrder() {
- return this.order;
- }
- @Around("myapp.SystemArchitecture.businessService()")
- public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
- int numAttempts = 0;
- PessimisticLockingFailureException lockFailureException;
- do {
- numAttempts++;
- try {
- return pjp.proceed();
- }
- catch(PessimisticLockingFailureException ex) {
- lockFailureException = ex;
- }
- }while(numAttempts <= this.maxRetries);
- throw lockFailureException;
- }
- }
3:更多
AOP知识,Spring AOP和Aspectj的知识。