一,基于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. [Hive_9] Hive 的排序

    0. 说明 全排序(order by) | 部分排序(sort by) | hash 分区(distribute by)  | cluster by 1. 前期准备 1.1 建表 create tab ...

  2. 关于Numba开源库(Python语法代码加速处理,看过一个例子,速度可提高6倍)

    关于Numba你可能不了解的七个方面 https://yq.aliyun.com/articles/222523 Python GPU加速 (很详细,有代码练习)https://blog.csdn.n ...

  3. linux c 语言之--fseek(),fseeko(),fseeko64()讲解 (转载)

    转载:http://blog.csdn.net/lemoncyb/article/details/16841317 fseek() 函数讲解: 函数定义: int fseek(FILE *stream ...

  4. Servlet(五):一个Servlet处理多个请求

    一.为什么要使用一个Servlet来处理多个请求? 当浏览器发送了一次请求到服务器时,servlet容器会根据请求的url-pattern找到对应的Servlet类,执行对应的doPost或doGet ...

  5. June 7. 2018 Week 23rd Thursday

    Half is worse than none at all. 一知半解比一无所知更痛苦. From Westworld. If we go looking for the truth, get th ...

  6. JDBC复习1

    1.什么是JDBC JDBC是java数据库连接技术的简称(Java DataBase Connectivity) jdbc是接口,jdbc驱动才是接口的实现,负责连接各种不同的数据库.jdbc的AP ...

  7. 在win10 64位系统安装 lxml (Python 3.5)

    本想直接用pip install lxml 命令安装完事,但是由于安装过程中跟VS的一些东西冲突怎么都安装不上,搜索到以下方法,问题解决. 步骤: 1.下载跟python匹配的.whl 文件(lxml ...

  8. Mac中selenium使用出现错误

    解决方案是: 首先通过brew 安装 $ brew install geckodriver 然后设置配置文件~/.bash_profile文件 export PATH=$PATH:/path/to/g ...

  9. python六十六课——单元测试(二)

    ''' 封装Person类 ''' class Person: def __init__(self,name,age): self.name=name self.age=age def getAge( ...

  10. [Python] 练习代码

    # from random import randrange # num = int(input('摇几次骰子: ')) # sides=int(input('筛子有几个面: ')) # sum=0 ...