zoukankan      html  css  js  c++  java
  • Mybatis+Spring实现Mysql读写分离


    使用spring AbstractRoutingDatasource实现多数据源

    
    public class DynamicDataSource extends AbstractRoutingDataSource {
        //写数据源
        private Object writeDataSource;
        //读数据源
        private Object readDataSource;    @Override
        public void afterPropertiesSet() {
            Assert.isNull(writeDataSource, "Property 'writeDataSource' is required");
            setDefaultTargetDataSource(writeDataSource);
            Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
            targetDataSources.put(DBTypeEnum.WRITE.name(), writeDataSource);
            if (null != readDataSource)
                targetDataSources.put(DBTypeEnum.READ.name(), readDataSource);
            setTargetDataSources(targetDataSources);
            super.afterPropertiesSet();
        }
    
        /**
         * 获取当前使用那个数据源
         */
        @Override
        protected Object determineCurrentLookupKey() {
            DBTypeEnum dataSource = DbContextHolder.getDbType();
            if (null == dataSource || dataSource == DBTypeEnum.WRITE)
                return DBTypeEnum.WRITE.name();
            return DBTypeEnum.READ.name();
        }
    
        public Object getWriteDataSource() {
            return writeDataSource;
        }
    
        public void setWriteDataSource(Object writeDataSource) {
            this.writeDataSource = writeDataSource;
        }
    
        public Object getReadDataSource() {
            return readDataSource;
        }
    
        public void setReadDataSource(Object readDataSource) {
            this.readDataSource = readDataSource;
        }
    }
    
    


    读写数据库类型

    
    public enum DBTypeEnum {
        WRITE, READ;
    }
    
    


    当前数据库配置上下文

    
    public class DbContextHolder {
        private static final ThreadLocal<DBTypeEnum> DATASOURCES = new ThreadLocal<DBTypeEnum>();
    
        private DbContextHolder() {
        }
    
        /**
         * 设置数据源
         *
         * @param dbType
         */
        public static void setDbType(DBTypeEnum dbType) {
            DATASOURCES.set(dbType.WRITE);
        }
    
        /*
        * 获取当前数据源
        * @return DBTypeEnum
        * */
        public static DBTypeEnum getDbType() {
            return DATASOURCES.get();
        }
    
        /**
         * 清除上下文数据
         */
        public static void clearDbType() {
            DATASOURCES.remove();
        }
    }
    
    


    自定义事务管理器

    
    public class DynamicDataSourceTransactionManager extends DataSourceTransactionManager {
        /**
         * 设置数据源
         */
        @Override
        protected void doBegin(Object transaction, TransactionDefinition definition) {
            boolean readOnly = definition.isReadOnly();
            if (readOnly)
                DbContextHolder.setDbType(DBTypeEnum.READ);
            DbContextHolder.setDbType(DBTypeEnum.WRITE);
            super.doBegin(transaction, definition);
        }
    
        /**
         * 清理本地线程数据源
         */
        @Override
        protected void doCleanupAfterCompletion(Object transaction) {
            super.doCleanupAfterCompletion(transaction);
            DbContextHolder.clearDbType();
        }
    }
    
    


    mybatis插件(拦截器)

    
    @Intercepts({
            @Signature(type = Executor.class, method = "update", args = {
                    MappedStatement.class, Object.class}),
            @Signature(type = Executor.class, method = "query", args = {
                    MappedStatement.class, Object.class, RowBounds.class,
                    ResultHandler.class})})
    public class DynamicPlugin implements Interceptor {
        private static final Logger _log = LoggerFactory.getLogger(DynamicPlugin.class);
        private static final String REGEX = ".*insert\u0020.*|.*delete\u0020.*|.*update\u0020.*";
        private static final Map<String, DBTypeEnum> cachaMap = new HashMap<String, DBTypeEnum>();
    
        @Override
        public Object intercept(Invocation invocation) throws Throwable {
            boolean isSynchronizationActive = TransactionSynchronizationManager.isSynchronizationActive();
            if (!isSynchronizationActive) {
                MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
                DBTypeEnum dbTypeEnum = null;
                if ((dbTypeEnum = cachaMap.get(ms.getId())) == null) {
                    //读方法
                    if (ms.getSqlCommandType().equals(SqlCommandType.SELECT)) {
                        //!selectKeu为自增id查询主键(SELECT LAST_INSERT_ID)方法,使用主库
                        if (ms.getId().contains(SelectKeyGenerator.SELECT_KEY_SUFFIX))
                            dbTypeEnum = DBTypeEnum.WRITE;
                        else {
                            BoundSql boundSql = ms.getSqlSource().getBoundSql(invocation.getArgs()[1]);
                            String sql = boundSql.getSql().toLowerCase(Locale.CHINA).replaceAll("[\t\n\r]", " ");
                            if (sql.matches(REGEX))
                                dbTypeEnum = DBTypeEnum.WRITE;
                            dbTypeEnum = DBTypeEnum.READ;
                        }
                    } else {
                        dbTypeEnum = DBTypeEnum.WRITE;
                    }
                    _log.warn("设置方法[{}] use [{}] Strategy, SqlCommandType [{}]..", ms.getId(), dbTypeEnum.name(), ms.getSqlCommandType().name());
                    cachaMap.put(ms.getId(), dbTypeEnum);
                }
                DbContextHolder.setDbType(dbTypeEnum);
            }
            return invocation.proceed();
        }
    
        @Override
        public Object plugin(Object target) {
            if (target instanceof Executor) {
                return Plugin.wrap(target, this);
            } else {
                return target;
            }
        }
    
        @Override
        public void setProperties(Properties properties) {
    
        }
    }
    
    
  • 相关阅读:
    个税
    MC9S08中断机制
    各大公司面试笔试
    uc/OSII 任务切换
    Source Insight 使用
    充70送70
    兔年大年30
    pip更新后报No module named pip
    MsSql Md5
    iOS UIImage扩展方法(category):放大、旋转、合并UIImage、增加渐变层、添加阴影、调节透明度、保存到相册
  • 原文地址:https://www.cnblogs.com/lovellll/p/10213947.html
Copyright © 2011-2022 走看看