问题:
开发过程中遇到一个坑,@Transactional注解方法下synchronized失效问题。
代码如下:
package com.example.demo.service.impl;
import com.example.demo.mapper.MoneyMapper;
import com.example.demo.model.po.MoneyPo;
import com.example.demo.model.vo.TrandingVo;
import com.example.demo.service.MoneyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import lombok.extern.slf4j.Slf4j;
/**
* @Author: yipeng
* @Date: 2021/6/18 21:09
*/
@Service
@Slf4j
public class MoneyServiceImpl implements MoneyService {
@Autowired
private MoneyMapper moneyMapper;
@Override
@Transactional
public synchronized boolean trading(TrandingVo trandingVo) {
MoneyPo fromUser = moneyMapper.getOneByUserName(trandingVo.getFromUserName());
MoneyPo toUser = moneyMapper.getOneByUserName(trandingVo.getToUserName());
if (fromUser.getMoney() > trandingVo.getMoney()) {
fromUser.setMoney(fromUser.getMoney() - trandingVo.getMoney());
toUser.setMoney(toUser.getMoney() + trandingVo.getMoney());
moneyMapper.update(fromUser);
moneyMapper.update(toUser);
return true;
}
log.error("trading error" + Thread.currentThread().getName());
return false;
}
}
现象:
1. synchronized锁trading函数还是锁trading函数中代码块,锁都失效
2. ReentrantLock锁trading函数中代码块也无济于事
3. redis分布式锁用于trading函数设想应该也无济于事
原因:
锁释放了,但事务却没提交。
并发场境下,出现多个线程拿到的数据库旧值而非最新值的现象,进而导致多线程安全bug。
解决方法:
1. 手动提交事务(不提倡)
2. 锁加在调用trading函数方法的上一级代码中
结论:
使用锁时候,注意锁的作用范围,诸如@Transactional或其他自定义的功能性注解,要注意锁作用域不全导致并发情况下与预期结果不一致的情况。