美文网首页
Spring主从数据库切换,事务失效

Spring主从数据库切换,事务失效

作者: MC_Honva | 来源:发表于2018-05-31 17:27 被阅读96次
    前言

    多数据库切换时候,存在事务,导致数据库切换失败,读写分离无法完成。其原因在于DataSourceTransactionManager类中,事务处理的方式,摘取部分源码,如下:

    @Override
        protected void doBegin(Object transaction, TransactionDefinition definition) {
            .......
                // Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
                // so we don't want to do it unnecessarily (for example if we've explicitly
                // configured the connection pool to set it already).
                if (con.getAutoCommit()) {
                    txObject.setMustRestoreAutoCommit(true);
                    if (logger.isDebugEnabled()) {
                        logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
                    }
                    con.setAutoCommit(false);
                }
                txObject.getConnectionHolder().setTransactionActive(true);
           .......
        }
    

    因为建立数据源链接在一些连接驱动中是非常耗时的处理,所以为了避免这样的操作,在事务处理的时候,会先把数据源放入缓存中,等待事务处理完成才会清除缓存,所以如果在service层中的方法中添加了事务,并且方法中存在切换数据源的操作,将会导致切换失败。情景如下:

    @Transactional
    public Integer updateType(TypeDto typeDto) {
            ....
            TypeModle oldTypeModle = typeDao.findById(typeDto.getId());
            ....
            return this.enumTypeDao.updateById(oldtypeModle);
        }
    
    解决方法及思路
    • 思路
      在获取事务锁定数据源之前切换数据源。

    • 方法一
      将事务处理放在DAO层,切面放在SERVICE层。

    //Service层
    @Before("execution(* cn.ymanager.service..*.*(..))")
        public void dbAspect(JoinPoint point){
            .....
        }
    //DAO层
    @Transactional
    public interface Dao extends BaseDao<Modle, Long> {
        ...........    
    }
    
    • 方法二
      如上所说,因为切换数据源的时候,事务先执行了,导致切换数据库失败。也可以从事务方法入手。在DataSourceTransactionManager类的dobegin方法中修改。
      创建自己的类,继承DataSourceTransactionManage,重写dobegin方法。因为dobegin方法是在类AbstractRoutingDataSource的determineCurrentLookupKey()前执行。
    public class SpayTransactionManager extends DataSourceTransactionManager {
    
        @Override
        protected void doBegin(Object transaction, TransactionDefinition definition) {
            ...
            //写入自己的逻辑判断,并且切换到自己想到数据库
            super.doBegin(transaction, definition);
        }
    }
    

    关于主从数据库切换可参考此篇文章
    SpringMVC主从数据库切换

    相关文章

      网友评论

          本文标题:Spring主从数据库切换,事务失效

          本文链接:https://www.haomeiwen.com/subject/wlxcsftx.html