• 使用 Spring 配置动态数据源实现读写分离


    最近搭建的一个项目需要实现数据源的读写分离,在这里将代码进行分享,以供参考。
    关键词:DataSource 、AbstractRoutingDataSource、AOP

    首先是配置数据源

    <!--读数据源配置-->
    <bean id="readDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"destroy-method="close">
    //配置省略
    </bean>
    
    <!--写数据源配置-->
    <bean id="writeDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"destroy-method="close">
    //配置省略
    </bean>
    
    <!-- 动态数据源 -->
    <bean id = "dataSource" class="com.potato.common.bean.DynamicDataSource" > 
      <!-- 已配置的数据源 -->   
     <property name="targetDataSources">      
      <map>          
          <entry key="READ" value-ref="readDataSource"/>          
          <entry key="WRITE" value-ref="writeDataSource"/>        
     </map>   
     </property>   
     <!-- 默认的数据源 -->  
     <property name="defaultTargetDataSource" ref="writeDataSource"/>
    </bean>

    数据源是如何切换的呢?通过动态数据源的配置我们知道原来是通过key来进行切换,这里要使用到org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource,我们可以编写自己的动态数据源类DynamicDataSource来继承它。

    public class DynamicDataSource extends AbstractRoutingDataSource {  
      @Override    
      protected Object determineCurrentLookupKey() {       
         return DataSourceContextHolder.getType();    
        }
    }

    还需要一个存放key的地方DataSourceContextHolder 为保证切换时线程安全我们使用ThreadLocal来保存我们的key。

    public class DataSourceContextHolder {
        private static final Logger LOGGER = LoggerFactory.getLogger(DataSourceContextHolder.class);
        public static final String DATA_SOURCE_WRITE = "WRITE";
        public static final String DATA_SOURCE_READ = "READ";
        // 线程本地环境
        private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
    
        // 设置数据源类型
        public static void setType(String type) {
            if(LOGGER.isDebugEnabled())
                LOGGER.debug("==============切换数据源,类型:"+type+"================");
            contextHolder.set(type);
        }
        // 获取数据源类型
        public static String getType() {
            return (contextHolder.get());
        }
        // 清除数据源类型
        public static void clearType() {
            contextHolder.remove();
        }
    }

    好了,我们可以通过操作DataSourceContextHolder来实现数据源动态的切换了。小伙伴们可能会说了,难道每次调用方法都要手动选择要切换的数据源类型?当然不是啦,Spring AOP登场。

    @Component
    @Aspect
    public class DynamicDataSourceAspect {
    
        @Pointcut("execution (* com.potato.orm.mapper.*.select*(..)) || execution (* com.potato.orm.mapper.*.count*(..)) ")
        public void readMethodPointcut() {}
    
        @Pointcut("execution (* com.potato.orm.mapper.*.insert*(..)) || execution (* com.potato.orm.mapper.*.update*(..)) || execution (* com.potato.orm.mapper.*.delete*(..))")
        public void writeMethodPointcut() {}
    
        @Before("readMethodPointcut()")
        public void switchReadDataSource(){
            //System.out.println("============切换到读数据源===========");
            DataSourceContextHolder.setType(DataSourceContextHolder.DATA_SOURCE_READ);
        }
    
        @Before("writeMethodPointcut()")
        public void switchWriteDataSource(){
            //System.out.println("=============切换到写数据源==========");
            DataSourceContextHolder.setType(DataSourceContextHolder.DATA_SOURCE_WRITE);
        }
    
    }

    好啦,在访问Mapper(本项目使用的是MyBatis啦,相当于是DAO)中查询方法时会切换到读数据源,增、删、改方法会切换到写数据源。

  • 相关阅读:
    如何在DOS中枚举PCI设备
    [Color]深入学习YCbCr色彩模型
    [Imm]Imm API学习笔记——输入法属性
    VBE_INFO(获取VBE信息)
    用VB写高效的图像处理程序 V2.0(2006524)
    ANSI环境下支持多语言输入的单行文本编辑器 V0.01
    分析外星人计算Pi的程序
    位运算模块mBit.bas
    [FileFormat]用VB写的高速GIF、JPEG 编码/解码 程序
    ANTLR笔记3 ANTLRWorks
  • 原文地址:https://www.cnblogs.com/moxiaotao/p/13079910.html
Copyright © 2020-2023  润新知