annotation+aop实现优雅的乐观锁重试

前言

在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());
    }
}
执行结果
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容