Spring 中 @Transactional and synchronized同时存在的问题
控制器代码
`
@PostMapping("/addExchange")
@ApiOperation(value = "兑换")
public R addExchange(@RequestBody AddExchangeDTO req){
AppUser user = ThreadUtil.getUser();
//校验交易密码
iAppUserService.checkTradePassword(user.getTradePassword(),req.getTradePassword());
//兑换
return R.status(hisExchangeService.addExchange(req,user.getId()));
}
`
1、正确的处理方式:事务中可以加锁
`
@Override
@Transactional(rollbackFor = Exception.class)
public boolean addExchange(AddExchangeDTO req, Integer userId) {
AppUser my = appUserService.getById(userId);
//操作价值
BigDecimal worth = new BigDecimal(req.getWorth());
//市价
BigDecimal nowPrice = hisIconPriceService.getNowPrice();
doExchange(req.getType(), my, worth, nowPrice);
return true;
}
@Override
//@Transactional(rollbackFor = Exception.class)
public synchronized void doExchange(Integer type, AppUser my, BigDecimal worth, BigDecimal nowPrice) {
//XU 兑换 U
if (type.equals(0)) {
XU_To_U(worth, my.getWalletXu(), nowPrice, my.getWalletId(), my.getId());
}
//U 兑换 XU
if (type.equals(1)) {
U_To_XU(worth, my.getWalletUsdt(), nowPrice, my.getWalletId());
}
}
`
2、错误的处理方式:锁中加事务,网络上很多人介绍这种处理方式
`
@Override
public synchronized boolean addExchange(AddExchangeDTO req, Integer userId) {
AppUser my = appUserService.getById(userId);
//操作价值
BigDecimal worth = new BigDecimal(req.getWorth());
//市价
BigDecimal nowPrice = hisIconPriceService.getNowPrice();
doExchange(req.getType(), my, worth, nowPrice);
return true;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void doExchange(Integer type, AppUser my, BigDecimal worth, BigDecimal nowPrice) {
//XU 兑换 U
if (type.equals(0)) {
XU_To_U(worth, my.getWalletXu(), nowPrice, my.getWalletId(), my.getId());
}
//U 兑换 XU
if (type.equals(1)) {
U_To_XU(worth, my.getWalletUsdt(), nowPrice, my.getWalletId());
}
}
`
说明:
-- U_To_XU 或 XU_To_U 会做U的转换 并做记录;
-- 第一种方式会保证数据的一致性。
-- 第二种方式无法保证数据的一致性;当部分业务抛出业务异常时,事务并没有回滚。