前言
在spring中徐块,樂觀鎖重試主要就是在while循環(huán)中catch OptimisticLockingFailureException異常未玻,再加上一定的重試限制,這基本是一個模板的代碼胡控,寫起來不太優(yōu)雅扳剿,而且也是一些重復(fù)代碼,因此就想如何消除這種模板代碼昼激。起初想的是有個callback回調(diào)函數(shù)包裝一下庇绽,后來想到了aop,再利用annotation橙困,對annotation做切面瞧掺,即可實(shí)現(xiàn)這模板代碼。
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);
}
}
}
}
// 實(shí)現(xiàn)Ordered接口是為了讓這個aop增強(qiáng)的執(zhí)行順序在事務(wù)之前
@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());
}
}
執(zhí)行結(jié)果