一,基于SSM框架的多数据源配置

1.创建DynamicDataSourceHolder用于持有当前线程中使用的数据源标识

public class DynamicDataSourceHolder {
    /**
     * 注意:数据源标识保存在线程变量中,避免多线程操作数据源时互相干扰
     */
    private static final ThreadLocal<String> THREAD_DATA_SOURCE = new ThreadLocal<String>();

    public static String getDataSource() {
        return THREAD_DATA_SOURCE.get();
    }

    public static void setDataSource(String dataSource) {
        THREAD_DATA_SOURCE.set(dataSource);
    }

    public static void clearDataSource() {
        THREAD_DATA_SOURCE.remove();
    }
}

2.创建一个DynamicDataSource,继承AbstractRoutingDataSource并重写determineCurrentLookupKey

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class DynamicDataSource extends AbstractRoutingDataSource {
    /**
     * override determineCurrentLookupKey
     * Description: 自动查找datasource
     */
    @Override
    protected Object determineCurrentLookupKey() {
        //从自定义的位置获取数据源标识
        return DynamicDataSourceHolder.getDataSource();
    }
}

3.配置多个数据源和第2步里创建的DynamicDataSource的bean

<!-- 引入jdbc配置文件 -->
    <bean id="propertyConfigurer"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:jdbc.properties" />
    </bean> 

    <!-- 配置数据源 -->
    <bean id="iFocusStructure" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
        <!-- 初始化连接大小 -->
        <property name="initialSize" value="${initialSize}" />
        <!-- 连接池最大数量 -->
        <property name="maxActive" value="${maxActive}" />
        <!-- 连接池最大空闲 -->
        <property name="maxIdle" value="${maxIdle}" />
        <!-- 连接池最小空闲 -->
        <property name="minIdle" value="${minIdle}" />
          <!-- 获取连接最大等待时间 -->
        <property name="maxWait" value="${maxWait}"/>
    </bean>

     <bean id="iFocusERA" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${driver2}"/>
        <property name="url" value="${url2}"/>
        <property name="username" value="${username2}"/>
        <property name="password" value="${password2}"/>
        <!-- 初始化连接大小 -->
        <property name="initialSize" value="${initialSize}" />
        <!-- 连接池最大数量 -->
        <property name="maxActive" value="${maxActive}" />
        <!-- 连接池最大空闲 -->
        <property name="maxIdle" value="${maxIdle}" />
        <!-- 连接池最小空闲 -->
        <property name="minIdle" value="${minIdle}" />
          <!-- 获取连接最大等待时间 -->
        <property name="maxWait" value="${maxWait}"/>
    </bean>

    <bean id="dataSource" class="com.yaming.hst.sys.util.DynamicDataSource">
         <property name="targetDataSources">
             <map key-type="java.lang.String">
                 <!-- 指定lookupKey和与之对应的数据源 -->
                 <entry key="iFocusStructure" value-ref="iFocusStructure"></entry>
                 <entry key="iFocusERA" value-ref="iFocusERA"></entry>
             </map>
         </property>
         <property name="defaultTargetDataSource" ref="iFocusStructure" />
     </bean>
  

4.代码如下:

@Service

public class UserService {

       @Autowired

       private UserDao userDao;

       @Autowired

       private ProjectDao projectDao;

       public List<User> selectUser() {

              return userDao.selectUser();

       }

       public List<Project> selectProject() {

              //切换到数据源iFocusERA

              DynamicDataSourceHolder.setDataSource("iFocusERA"); 

              return projectDao.getAllProjects();

       }

}

5.

但是,如果每次切换数据源时都调用DynamicDataSourceHolder.setDataSource("xxx")就显得十分繁琐了,而且代码量大了很容易会遗漏,后期维护起来也比较麻烦。能不能直接通过注解的方式指定需要访问的数据源呢,比如在dao层使用@DataSource("xxx")就指定访问数据源xxx?当然可以!前提是,再加一点额外的配置。

6.定义一个名为DataSource的注解,作为切点:

import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;

@Target({ ElementType.TYPE,ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {
    String value();
}

7.配置切面,定义AOP切面以便拦截所有带有注解@DataSource的方法,取出注解的值作为数据源标识放到DynamicDataSourceHolder的线程变量中

import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DataSourceAspect {
    private static final Logger logger = LoggerFactory.getLogger(DataSourceAspect.class);
    /**
     * 拦截目标方法,获取由@DataSource指定的数据源标识,设置到线程存储中以便切换数据源
     * @param point
     * @throws Exception
     */
    public void intercept(JoinPoint point) throws Exception {
       Class<?> target = point.getTarget().getClass();
       MethodSignature signature = (MethodSignature) point.getSignature();
       // 默认使用目标类型的注解,如果没有则使用其实现接口的注解
       for (Class<?> clazz : target.getInterfaces()) {
           resolveDataSource(clazz, signature.getMethod());
       }
       resolveDataSource(target, signature.getMethod());
   }

   /**
    * 提取目标对象方法注解和类型注解中的数据源标识
    * @param clazz
    * @param method
    */
   private void resolveDataSource(Class<?> clazz, Method method) {
       try {
           Class<?>[] types = method.getParameterTypes();
           // 默认使用类型注解
           if (clazz.isAnnotationPresent(DataSource.class)) {
               DataSource source = clazz.getAnnotation(DataSource.class);
               DynamicDataSourceHolder.setDataSource(source.value());
           }
           // 方法注解可以覆盖类型注解
           Method m = clazz.getMethod(method.getName(), types);
           if (m != null && m.isAnnotationPresent(DataSource.class)) {
               DataSource source = m.getAnnotation(DataSource.class);
               DynamicDataSourceHolder.setDataSource(source.value());
           }
       } catch (Exception e) {
           logger.error(clazz + ":" + e.getMessage());
       }
   }
}

8.最后在spring配置文件中配置拦截规则就可以了,比如拦截service层或者dao层的所有方法

<bean id="dataSourceAspect" class="com.yaming.hst.sys.util.DataSourceAspect" />
    <aop:config>
        <aop:aspect ref="dataSourceAspect">
            <!-- 拦截所有service方法 -->
            <aop:pointcut id="dataSourcePointcut" expression="execution(* com.yaming.hst.*.dao.*.*(..))"/>
            <aop:before pointcut-ref="dataSourcePointcut" method="intercept" />
        </aop:aspect>
    </aop:config>

9. 这样就可以直接在类或者方法上使用注解@DataSource来指定数据源,不需要每次都手动设置了。

@DataSource("iFocusERA")
public interface FeatureBigDataVersionMapper {

    int deleteByPrimaryKey(Integer id);

    int insert(FeatureBigDataVersion record);

}

10. 提示:注解@DataSource既可以加在方法上,也可以加在接口或者接口的实现类上,优先级别:方法>实现类>接口。也就是说如果接口、接口实现类以及方法上分别加了@DataSource注解来指定数据源,则优先以方法上指定的为准。

11.jdbc.properties

driver=
url=
username=
password=

driver2=
url2=
username2=
password2=

initialSize=0

maxActive=20

maxIdle=5

minIdle=1

maxWait=60000

mysql之整合ssm多数据源配置的更多相关文章

  1. 6_1.springboot2.x整合JDBC与数据源配置原理解析

    1.引言 对于数据访问层,无论是SQL还是NOSQL,Spring Boot默认采用整合 Spring Data的方式进行统一处理,添加大量自动配置,屏蔽了很多设置.引入各种xxxTemplate,x ...

  2. mysql连接超时与jndi数据源配置

    昨天有运营说添加活动不能用了,我就看了一下后台日志,发现访问数据库是报错: at java.lang.Thread.run(Thread.java:722) Caused by: com.mysql. ...

  3. hibernate与ssm多数据源配置

    hibernate: 1.配置多个数据源,比如2个:hibernate.cfg1.xml~hibernate.cfg8.xml <?xml version='1.0' encoding='UTF ...

  4. ssm多数据源配置

    1.在.properties配置文件中 添加第二个数据源信息(type2,driver2, url2,username2,pawwword2) 2.修改spring-context.xml(src/m ...

  5. 手把手整合SSM框架

    前言 如果看过前几篇文章,对 Spring 和 MyBatis 有了一定了解,一定想上手试试.这篇文章从 0 到 1,手把手整合 SSM (Spring.Spring MVC.MyBatis). 本篇 ...

  6. 快速搭建springboot框架以及整合ssm+shiro+安装Rabbitmq和Erlang、Mysql下载与配置

    1.快速搭建springboot框架(在idea中): file–>new project–>Spring Initializr–>next–>然后一直下一步. 然后复制一下代 ...

  7. SSM框架之多数据源配置

    多数据源的应用场景:主要是数据库拆分后,怎样让多个数据库结合起来来达到业务需求. SSM框架(Spring+SpringMVC+MyBatis(MyBatis-Plus))是目前最常用的,此次仍然是m ...

  8. Spring Boot 入门系列(二十三)整合Mybatis,实现多数据源配置!

    d之前介绍了Spring Boot 整合mybatis 使用注解方式配置的方式实现增删改查以及一些复杂自定义的sql 语句 .想必大家对spring boot 项目中,如何使用mybatis 有了一定 ...

  9. coreseek(sphinx)安装2(mysql数据源配置和测试)

    Windows操作系统下 mysql数据源配置: 主要步骤:  配置mysql数据源配置文件->生成索引->开启索引   (三步) coreseek\etc\csft_mysql.conf ...

随机推荐

  1. C# -- 随机数(Random)的使用

    使用随机数产生一组大乐透号码 1. C#代码 1 Console.WriteLine("===============大乐透===红色球==============="); Lis ...

  2. puppet 横向扩展(三)

    Table of Contents 1. 概述 2. 实验环境 3. 实验步骤 3.1. 机器B 的配置 3.2. 机器A 的配置 3.3. 测试配置结果 概述 横向扩展实验之三 – 将CA 认证服务 ...

  3. 【工具大道】ssh登录Linux服务器,并显示图形化界面

    本文地址 点击关注微信公众号 "程序员的文娱情怀" 分享提纲: 1. 概述 2. mac版实现ssh登录,显示图形化 1. 概述 平时ssh登录到Linux服务器都是在命令行下进行 ...

  4. docker-machine on azure

    1.准备Azure的虚拟机,安装docker-machine 由于azure虚拟机的管理员账号不是root,所以这里我们使用自己创建的管理员yy 1.base=https://github.com/d ...

  5. [转自机器之心] 刚入校门的PhD们还可以抢救一下(读研读博指南)

    本文作者 Lucy A. Taylor 最近博士毕业,取得了牛津大学跨学科生物科学博士学位. 读博是件难事,一路上可能会遇到很多挫折.失败.崩溃时刻.Lucy 多么希望在开始读博时就能收到一些有益的建 ...

  6. VMware15安装MAC(MAC OS 10.13)(OS X 10.14)原版可升级最新可解锁macOS Unlocker3.0(OS X 10.13)

      目录树 1.1.2安装环境: 1.1.3所需资源: 1.1.4 Unlocker 3.0解锁 1.1.5 配置环境 1.1.6开始安装 1.1.7开启虚拟机进入MAC安装界面 1.1.8 macO ...

  7. redis单例模式写法

    <?php /**只看红色重点 * =========================================================== * ZW_Memory_Cache * ...

  8. 003_python学习之 字符串前'r'的用法

    在打开文件的时候open(r'c:\....') 加r和不加''r是有区别的 'r'是防止字符转义的 如果路径中出现'\t'的话 不加r的话\t就会被转义 而加了'r'之后'\t'就能保留原有的样子 ...

  9. 3.if结构

    一.简单if结构1.定义:程序的条件判断2.语法:if(条件){ 语句块1}else{ 语句块2}语句块33:说明:条件必须是条件表达式,其结果必须是一个boolean类型 else是可选项,可以不写 ...

  10. apt-get update 更新 ubuntu时出现Hash sum mismatch的原因及解决方法

    $ sudo apt-get update ...... Hit http://mirrors.163.com trusty/main Sources                          ...