• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    Spring AOP 动态多数据源的实例详解

     Spring AOP 动态多数据源的实例详解

    当项目中使用到读写分离的时候,我们就会遇到多数据源的问题。多数据源让人最头痛的,不是配置多个数据源,而是如何能灵活动态的切换数据源。例如在一个spring和Mybatis的框架的项目中,我们在spring配置中往往是配置一个dataSource来连接数据库,然后绑定给sessionFactory,在dao层代码中再指定sessionFactory来进行数据库操作。

     

    正如上图所示,每一块都是指定绑死的,如果是多个数据源,也只能是下图中那种方式。

    可看出在Dao层代码中写死了两个SessionFactory,这样日后如果再多一个数据源,还要改代码添加一个SessionFactory,显然这并不符合开闭原则。

    那么正确的做法应该是:

    具体代码与配置如下:

    1、applicationContext-mgr.xml

    ?xml version="1.0" encoding="utf-8" ?>
    beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xmlns:aop="http://www.springframework.org/schema/aop"
      xmlns:context="http://www.springframework.org/schema/context" 
      xmlns:tx="http://www.springframework.org/schema/tx"
      xmlns:p="http://www.springframework.org/schema/p"
      xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
    http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
      !-- use annotation -->
      context:annotation-config />
        context:component-scan base-package="com.carl.o2o.**.mgr">
      /context:component-scan>
    
      !-- master -->
      bean id="master" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        property name="driverClass" value="${driverClassName_master}"/>
        property name="user" value="${username_master}"/>
        property name="password" value="${password_master}"/>
        property name="jdbcUrl" value="${url_master}?Unicode=truecharacterEncoding=UTF-8allowMultiQueries=true"/>
    
        property name="maxPoolSize" value="150"/> 
        property name="minPoolSize" value="10"/> 
        property name="initialPoolSize" value="20"/> 
        property name="maxIdleTime" value="3600"/> 
        property name="acquireIncrement" value="10"/> 
        property name="idleConnectionTestPeriod" value="1800"/>  
      /bean>
    
      !-- slave -->
      bean id="slave" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        property name="driverClass" value="${driverClassName_slave}"/>
        property name="user" value="${username_slave}"/>
        property name="password" value="${password_slave}"/>
        property name="jdbcUrl" value="${url_slave}?Unicode=truecharacterEncoding=UTF-8"/>
    
        property name="maxPoolSize" value="150"/> 
        property name="minPoolSize" value="10"/> 
        property name="initialPoolSize" value="20"/> 
        property name="maxIdleTime" value="3600"/> 
        property name="acquireIncrement" value="10"/> 
        property name="idleConnectionTestPeriod" value="1800"/>  
      /bean>
    
      !-- spring 动态数据源 -->
      bean id="dynamicDataSource" class="com.carl.dbUtil.DynamicDataSource">
        property name="targetDataSources"> 
          map key-type="java.lang.String"> 
            entry key="slave" value-ref="slave" /> 
          /map> 
        /property> 
        property name="defaultTargetDataSource" ref="master" />   
      /bean> 
    
      !-- mybatis mapper config -->
      bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        property name="dataSource" ref="dynamicDataSource"/>
        property name="configLocation" value="classpath:o2o_mybatis_config.xml"/>
        property name="mapperLocations" >
          list>
            value>classpath:sqlMap/*.xml/value>
            value>classpath*:/com/carl/o2o/**/*.xml/value>
          /list>
        /property>
      /bean>
    
      bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        constructor-arg index="0" ref="sqlSessionFactory">/constructor-arg>
      /bean>
    
      bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        property name="basePackage" value="com.carl.o2o.**.mgr.dao" />
      /bean>
    
      !-- 多数据源 aop -->
      bean id="DataSourceAspect" class="com.carl.dbUtil.DataSourceAspect" />
      aop:config> 
        aop:advisor pointcut="execution(* com.carl.o2o.mgr.*.*(..))" advice-ref="DataSourceAspect" />
      /aop:config> 
    
      !-- 事务 -->
      bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
        property name="dataSource" ref="dynamicDataSource">/property>
      /bean>
     /beans>
    
    

    2、DynamicDataSource

    DynamicDataSource使用Spring中的代码结合AOP实现多数据源切换.

    public class DynamicDataSource extends AbstractRoutingDataSource {
      public DynamicDataSource() {
      }
    
      protected Object determineCurrentLookupKey() {
        return DBContextHolder.getDbType();
      }
    
      public Logger getParentLogger() {
        return null;
      }
    }
    
    

    3、DBContextHolder

    DynamicDataSource的辅助类,用于实际的切换多数据源。

    public class DBContextHolder {
      private static ThreadLocalString> contextHolder = new ThreadLocal();
      public static String MASTER = "master";
      public static String SLAVE = "slave";
    
      public DBContextHolder() {
      }
    
      public static String getDbType() {
        String db = (String)contextHolder.get();
        if(db == null) {
          db = MASTER;
        }
    
        return db;
      }
    
      public static void setDbType(String str) {
        contextHolder.set(str);
      }
    
      public static void setMaster() {
        contextHolder.set(MASTER);
      }
    
      public static void setSlave() {
        contextHolder.set(SLAVE);
      }
    
      public static void clearDBType() {
        contextHolder.remove();
      }
    }
    
    

    4、DataSourceAspect

    多数据源AOP切面编程实现。

    public class DataSourceAspect implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice {
      private static final Logger log = LogManager.getLogger(DataSourceAspect.class);
    
      public DataSourceAspect() {
      }
    
      public void before(Method m, Object[] args, Object target) throws Throwable {
        try {
          if(m != null) {
            if((m.getName().startsWith("list") || m.getName().startsWith("select") || m.getName().startsWith("get") 
            || m.getName().startsWith("count"))  !m.getName().contains("FromMaster")) {
              DBContextHolder.setDbType("slave");
            } else {
              DBContextHolder.setDbType("master");
            }
          }
        } catch (Exception var5) {
          log.error("data source aspect error.", var5);
        }
    
      }
    
      public void after(JoinPoint point) {
        log.info("clear db type after method.current id {}", new Object[]{Long.valueOf(Thread.currentThread().getId())});
        DBContextHolder.clearDBType();
      }
    
      public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
      }
    
      public void afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable {
        log.info("current db type {} when exception", new Object[]{DBContextHolder.getDbType()});
        DBContextHolder.setDbType("master");
      }
    }
    
    

    以上就是 Spring AOP 动态多数据源的实例详解,如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

    您可能感兴趣的文章:
    • Spring+Mybatis 实现aop数据库读写分离与多数据库源配置操作
    • spring aop action中验证用户登录状态的实例代码
    • 利用spring AOP记录用户操作日志的方法示例
    • 详解SpringBoot AOP 拦截器(Aspect注解方式)
    • Spring AOP实现Redis缓存数据库查询源码
    上一篇:详解Spring mvc ant path的使用方法
    下一篇:Spring mvc 分步式session的实例详解
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    Spring AOP 动态多数据源的实例详解 Spring,AOP,动态,多,数据源,