前言
在spring中,乐观锁重试主要就是在while循环中catch OptimisticLockingFailureException异常,再加上一定的重试限制,这基本是一个模板的代码,写起来不太优雅,而且也是一些重复代码,因此就想如何消除这种模板代码。起初想的是有个callback回调函数包装一下,后来想到了aop,再利用annotation,对annotation做切面,即可实现这模板代码。
talk is cheap,show me the code
// annotation
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface OptFailureRetry {
int retryTimes() default 10;
}
// aop
@Component
@Aspect
public class OptimisticLockingFailureRetryAop implements Ordered {
@Pointcut("@annotation(com.darcy.leon.demo.annotation.OptFailureRetry)")
public void retryOnOptFailure() {
}
@Around("retryOnOptFailure()")
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
Signature signature = pjp.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method targetMethod = methodSignature.getMethod();
OptFailureRetry annotation = targetMethod.getAnnotation(OptFailureRetry.class);
int retryTimes = annotation.retryTimes();
while (true) {
try {
return pjp.proceed();
} catch (OptimisticLockingFailureException e) {
if (retryTimes > 0) {
retryTimes--;
System.out.println(Thread.currentThread().getName() + ": optimistic locking failure, remaining retry times:" + retryTimes);
} else {
throw new OverRetryException("retry " + annotation.retryTimes() + " times", e);
}
}
}
}
// 实现Ordered接口是为了让这个aop增强的执行顺序在事务之前
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
// 重试超限异常
public class OverRetryException extends RuntimeException {
public OverRetryException(Throwable cause) {
super(cause);
}
public OverRetryException(String message, Throwable cause) {
super(message, cause);
}
}
test case
// model
@Data
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String username;
@Version
private Integer version;
}
// dao
@Repository
public interface UserDao extends CrudRepository<User, Integer> {
}
// service
@Service
public class UserService {
@Autowired
private UserDao userDao;
@OptFailureRetry
@Transactional
public void updateWithTransactional() {
User user = new User();
user.setUsername("hello aop");
userDao.save(user);
System.out.println(userDao.findAll());
throw new OptimisticLockingFailureException("test roll back");
}
}
// Test类
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTest {
@Autowired
private UserDao userDao;
@Autowired
private UserService userService;
@Before
public void setUp() {
User user = new User();
user.setUsername("haha");
userDao.save(user);
}
@Test
public void testUpdateWithTransactional() {
try {
userService.updateWithTransactional();
} catch (OverRetryException e) {
e.printStackTrace();
}
System.out.println("=========================");
System.out.println(userDao.findAll());
}
}

网友评论