以下是伪代码
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.如果加了索引,则只会锁这一行。



