java声明式事务-实现乐观锁
注意 mysql 隔离级别
事务
自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Retry {
int value() default 3; // 重试次数
}
@Aspect
@Component
public class RetryAspect {
private static final Logger log = LoggerFactory.getLogger(RetryAspect.class);
@Pointcut("@annotation(com.dd.mall.annotation.Retry)")
public void retryPointcut() {
}
@Around("retryPointcut() && @annotation(retry)")
public Object tryAgain(ProceedingJoinPoint joinPoint, Retry retry) throws Throwable {
int count = 0;
do {
count++;
try {
return joinPoint.proceed();
} catch (ApiException e) {
if (count > retry.value()) {
log.error("Retry failed!");
return CommonResult.failed("请求流量过大,请稍后再试");
}
}
} while (true);
}
}
@Autowired
private PlatformTransactionManager transactionManager;
private final BiPredicate<BigDecimal, BigDecimal> isDepositEnough = (deposit, value) -> deposit.compareTo(value) > 0;
@Retry
@Override
public CommonResult<UserChangeBalanceDTO> deductionOptimisticProductSku(Long mallProductId, Long mallProductSkuId, Integer mallProductNumber, BigDecimal integralPrice, BigDecimal changeJf, Long userId) {
DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
transactionDefinition.setIsolationLevel(DefaultTransactionDefinition.ISOLATION_READ_COMMITTED);
transactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager, transactionDefinition);
return transactionTemplate.execute((status) -> {
// 获取账户详情
BigDecimal userIntegralBalance = integralBalanceDao.getUserIntegralBalance(userId);
BigDecimal consumeIntegral = changeJf != null ? changeJf : integralPrice.multiply(BigDecimal.valueOf(mallProductNumber));
if (!isDepositEnough.test(userIntegralBalance, consumeIntegral)) {
status.setRollbackOnly();
return CommonResult.failed("积分不足");
}
BigDecimal updateUserIntegral = userIntegralBalance.subtract(consumeIntegral);
if (!isDepositEnough.test(updateUserIntegral, BigDecimal.ZERO)) {
status.setRollbackOnly();
return CommonResult.failed("积分不足");
}
// 获取库存
Integer jfMallProductStock = mallProductSkuDao.getJfMallProductStock(mallProductSkuId);
if (!isDepositEnough.test(BigDecimal.valueOf(jfMallProductStock), BigDecimal.valueOf(mallProductNumber))) {
status.setRollbackOnly();
return CommonResult.failed("库存不足");
}
BigDecimal updateProductStock = BigDecimal.valueOf(jfMallProductStock).subtract(BigDecimal.valueOf(mallProductNumber));
if (!isDepositEnough.test(updateProductStock, BigDecimal.ZERO)) {
status.setRollbackOnly();
return CommonResult.failed("库存不足");
}
int r1 = integralBalanceDao.updateUserIntegralBalance(userId, userIntegralBalance, updateUserIntegral);
int r2 = mallProductSkuDao.updateMallProductSkuStock(userId, mallProductSkuId, jfMallProductStock, updateProductStock.intValue());
if (r1 != 1 || r2 != 1) {
status.setRollbackOnly();
// 失败,抛出重试异常,执行重试
throw new ApiException(ResultCode.TO_MANY_REQUEST);
} else {
// 剩余积分
return CommonResult.success(new UserChangeBalanceDTO.Builder().residueBalance(userIntegralBalance.subtract(consumeIntegral)).build());
}
});
}
UPDATE XXXXX
SET balance= #{nowAtm},
update_time = now(),
update_user = #{userId}
WHERE balance = #{balance}
and ID = #{researchGroupId}