【问题排查】select for upate 引起的问题

 
 
一. 代码说明
  1. M2方法的预期作用是根据id值(主键)加行锁,整个方法放在事务中执行
  2. M1方法调用M2方法
public class C
{
    public void M1()
    {
        this.M2();
    }
    
    @Transactional
    public void M2()
    {
        String sql="select * from t1 where id=1 for update";
        executeSql(sql);
        
        // 其它的一些事务操作
    }
}

 

二. 问题
1. M2方法事务未生效,并排除异常
select * from t1 where id=1 for update --readonly

 

三. 原因分析
  1. 数据库是一主多从结构,读写分离
  2. 方法上加@Transactional注解,不管是查询还是增删改,都可以保证走主库,可是异常提示"readonly",说明select语句走了从库
  3. M1和M2在同一个类C中,this.M2()语句并没有使用类C在容器中的代理对象,而是使用原生对象调用M2方法,故@Transactional注解未生效
  4. 由于@Transactional未生效,又因为"select * from t1 where id=1 for update"是读语句,会主动走从库,从库又是只读的,所以会抛出readonly异常
 
四. 解决方案
  1. 单独的类中调用:在单独的类中使用类C的代理对象调用M2方法
  2. 类C中操作:从IOC容器获取代理对象
public void M1() {
    C c = SpringUtils.getBean(C.class);
    c.M2();
}

 

  1. 类C中操作:在类中定义代理对象并使用
@Autowired
private C c1;

public void M1() {

    c1.M2();
}

 

 

posted @ 2021-05-26 12:06    阅读(50)  评论(0编辑  收藏  举报