1.@transcational注解和锁同时使用会造成锁失效的问题
以下是伪代码
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 updateXNumRepo(){
//当前数据库读取Num数
int currentNum = XXDao.getCurrentNum();
//更新
XXDao.updateNum(currentNum)
}
1.1 注意,还没有完结,针对上面的解决方案,如果是在同一个事务中非事务方法调用事务方法将会出现事务失效的问题。
上面的updateXNum()调用 updateXNumRepo()方法的时候,此时就算updateXNumRepo方法打了事务注解,但他的事务还是会失效,属于spring代理的时候,代理对象机制问题。
若要解决这个问题,updateXNum需要写在另一个serviceA中,再用serviceA.updateXNum()方法,或者注入自己本身service再调用也可以 代码如下:
class AServiceImpl implements AService{
// 注入一下本service对象去调用 解决同一个service中非事务方法调用事务方法,事务失效问题。
@Autowired
private AService aservice;
// 再用一个方法去调用被打上事务注解的方法,本方法加上synchronized同步锁
public synchronized Response updateXNum(){
// 在此处通过新注入aservice去调用即可解决
return aservice.updateXNumRepo();
}
@Transactional(rollbackFor = Exception.class)
public Response updateXNumRepo(){
//当前数据库读取Num数
int currentNum = XXDao.getCurrentNum();
//更新
XXDao.updateNum(currentNum)
}
}
2.Mysql开启事务时update操作锁表的行为
1.查看自己当前的数据库是否开启了自动提交事务。
select @@autocommit;
若为 1 要设置为 0 关闭自动提交事务。
mysql开启事务在update操作的时候会锁表
1.若update的字段没有索引,则会锁住整张表
2.如果加了索引,则只会锁这一行。