以下是伪代码
class aSevice{ // 方式一 synchronized 给事务加锁 @Transactional(rollbackFor = Exception.class) public synchronized Response updateXNum(){ //当前数据库读取Num数 int currentNum = XXDao.getCurrentNum(); //更新 XXDao.updateNum(currentNum) } // 方式二 Lock手动上锁 @Transactional(rollbackFor = Exception.class) public Response updateXNum(){ Lock.lock(); try{ //当前数据库读取Num数 int currentNum = XXDao.getCurrentNum(); //更新 XXDao.updateNum(currentNum) }catch(Exception e){ }finally{ Lock.unlock(); } } }
上面这两种方式给添加的事务的方法加锁都是无效的,原因在于Transactional注解使用了AOP动态代理,当锁释放时代理的事务还未结束就又有新的线程进来,造成事务未提交而又开始读取数据操作数据库的问题
解决方案:让锁的范围大于事务包扩的范围即可
// 再用一个方法去调用被打上事务注解的方法,本方法加上synchronized同步锁 public synchronized Response updateXNum(){ return updateXNumRepo(); } @Transactional(rollbackFor = Exception.class) public Response updateXNumRepo(){ //当前数据库读取Num数 int currentNum = XXDao.getCurrentNum(); //更新 XXDao.updateNum(currentNum) } //Lock方式的同步锁也是同理 public Response updateXNum(){ Lock.lock(); try{ return updateXNumRepo(); }catch(Exception e){ }finally{ Lock.unlock(); } } @Transactional(rollbackFor = Exception.class) public Response updateXNum(){ //当前数据库读取Num数 int currentNum = XXDao.getCurrentNum(); //更新 XXDao.updateNum(currentNum) }2.Mysql开启事务时update操作锁表的行为
1.查看自己当前的数据库是否开启了自动提交事务。
select @@autocommit;
若为 1 要设置为 0 关闭自动提交事务。
mysql开启事务在update操作的时候会锁表1.若update的字段没有索引,则会锁住整张表
2.如果加了索引,则只会锁这一行。