druid多数据源配置

一、druid简介

  Druid首先是一个数据库连接池,但它不仅仅是一个数据库连接池,它还包含一个ProxyDriver,一系列内置的JDBC组件库,一个SQL Parser。

  Druid是目前最好的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池,包括DBCP、C3P0、BoneCP、Proxool、JBoss DataSource。Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。

  Druid 是目前比较流行的高性能的,分布式列存储的OLAP框架(具体来说是MOLAP)。它有如下几个特点:

  一. 亚秒级查询

   druid提供了快速的聚合能力以及亚秒级的OLAP查询能力,多租户的设计,是面向用户分析应用的理想方式。

  二.实时数据注入

  druid支持流数据的注入,并提供了数据的事件驱动,保证在实时和离线环境下事件的实效性和统一性

  三.可扩展的PB级存储

   druid集群可以很方便的扩容到PB的数据量,每秒百万级别的数据注入。即便在加大数据规模的情况下,也能保证时其效性

  四.多环境部署

  druid既可以运行在商业的硬件上,也可以运行在云上。它可以从多种数据系统中注入数据,包括hadoop,spark,kafka,storm和samza等

  五.丰富的社区

二、druid多数据源使用

  1.直接配置

  配置两个 dataSource,两个sqlSessionFactory,两个transactionManager,以及关键的地方在于MapperScannerConfigurer 的配置——使用sqlSessionFactoryBeanName属性,注入不同的sqlSessionFactory的名称,这样就为不同的数据库对应的 mapper 接口注入了对应的 sql于master-slave类型的多数据源配置而言不太适应,不支持分布式事务

  2.基于AbstractRoutingDataSource和AOP的多数据源配置

  我们自己定义一个DataSource类ThreadLocalRountingDataSource,来继承AbstractRoutingDataSource,然后在配置文件中向ThreadLocalRountingDataSource注入 master 和 slave 的数据源,然后通过 AOP 来灵活配置。

  applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd> <!-- 启动spring注解 -->
<context:annotation-config/>
<!-- 扫描注解所在的包 -->
<context:component-scan base-package="com.example"/>
<!-- 启动aop注解 -->
<aop:aspectj-autoproxy proxy-target-class="true"/> <!-- 引入属性文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${driver}"/>
<property name="url" value="${url}"/>
</bean>
-->
<!-- 配置数据源master -->
<bean id="dataSourceMaster" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="driverClassName" value="${driver}"/>
<property name="url" value="${url}" />
<!-- 初始化连接大小 -->
<property name="initialSize" value="0" />
<!-- 连接池最大使用连接数量 -->
<property name="maxActive" value="20" />
<!-- 连接池最小空闲 -->
<property name="minIdle" value="1" />
<!-- 连接池最大空闲 -->
<property name="maxIdle" value="20" />
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="60000" />
</bean>
<!-- 配置数据源master -->
<bean id="dataSourceSlave" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="driverClassName" value="${driver}"/>
<property name="url" value="${url_slave}" />
<!-- 初始化连接大小 -->
<property name="initialSize" value="0" />
<!-- 连接池最大使用连接数量 -->
<property name="maxActive" value="20" />
<!-- 连接池最小空闲 -->
<property name="minIdle" value="0" />
<!-- 连接池最大空闲 -->
<property name="maxIdle" value="20" />
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="60000" />
</bean>
<bean id="dataSource" class="com.example.util.ThreadLocalRountingDataSource">
<property name="targetDataSources">
<map key-type="com.example.enums.DataSources">
<entry key="MASTER" value-ref="dataSourceMaster" />
<entry key="SLAVE" value-ref="dataSourceSlave"/>
</map>
</property>
<property name="defaultTargetDataSource" ref="dataSourceMaster"></property> </bean> <!-- 配置SQLSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<!-- 加载映射文件 -->
<property name="mapperLocations" value="classpath*:/com/example/dao/*Mapper.xml"></property>
</bean> <!-- 接口方式 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.example.dao"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean> </beans>

  1.定义一个DataSource枚举类

//定义一个enum来表示不同的数据源
public enum DataSources {
MASTER,SLAVE
}

  2.ThreadLocalRountingDataSource,继承AbstractRoutingDataSource

public class ThreadLocalRountingDataSource extends AbstractRoutingDataSource{

    @Override
protected Object determineCurrentLookupKey() {
// TODO Auto-generated method stub
return DataSourceTypeManager.get();
} }

  3.DataSourceTypeManager

//通过 TheadLocal 来保存每个线程选择哪个数据源的标志(key)

public class DataSourceTypeManager {

    private static final ThreadLocal<DataSources> dataSourceTypes=new ThreadLocal<>();

    public static DataSources get(){
return dataSourceTypes.get();
} public static void set(DataSources dataSourceType){
dataSourceTypes.set(dataSourceType);
} public static void reset(){
dataSourceTypes.set(DataSources.MASTER);
}
}

  4.aop管理

@Aspect
@Component
public class DataSourceInterceptor { @Pointcut("execution(public * com.example.service..*.selectByPrimaryKey(..))")
public void dataSourceMaster(){ }; @Before("dataSourceMaster()")
public void before(JoinPoint jp){
DataSourceTypeManager.set(DataSources.MASTER);
}
//...
/*这里我们定义了一个 Aspect 类,我们使用 @Before 来在符合
* @Pointcut("execution(public * net.aazj.service..*.selectByPrimaryKey(..))") 中的方法被调用之前,
* 调用 DataSourceTypeManager.set(DataSources.SLAVE) 设置了 key 的类型为 DataSources.MASTER,
* 所以 dataSource 会根据key=DataSources.MASTER 选择 dataSourceSlave 这个dataSource。
* 所以该方法对于的sql语句会在slave数据库上执行.
* 我们可以不断的扩充 DataSourceInterceptor这个 Aspect,在中进行各种各样的定义,
* 来为某个service的某个方法指定合适的数据源对应的dataSource。
* 这样我们就可以使用 Spring AOP 的强大功能来,十分灵活进行配置了。
*/
}

  当调用selectByPrimaryKey方法的时候会进入切面类中切换数据源,方法调用完毕会把数据源切换回来

三、AbstractRoutingDataSource原理

源码:

 public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean
void afterPropertiesSet() throws Exception;
 
    @Override
    public void afterPropertiesSet() {
        if (this.targetDataSources == null) {
            throw new IllegalArgumentException("Property 'targetDataSources' is required");
        }
        this.resolvedDataSources = new HashMap<Object, DataSource>(this.targetDataSources.size());
        for (Map.Entry<Object, Object> entry : this.targetDataSources.entrySet()) {
            Object lookupKey = resolveSpecifiedLookupKey(entry.getKey());
            DataSource dataSource = resolveSpecifiedDataSource(entry.getValue());
            this.resolvedDataSources.put(lookupKey, dataSource);
        }
        if (this.defaultTargetDataSource != null) {
            this.resolvedDefaultDataSource = resolveSpecifiedDataSource(this.defaultTargetDataSource);
        }
    }

  targetDataSources 是我们在xml配置文件中注入的 dataSourceMaster 和 dataSourceSlave. afterPropertiesSet方法就是使用注入的dataSourceMaster 和 dataSourceSlave来构造一个HashMap——resolvedDataSources。方便后面根据 key 从该map 中取得对应的dataSource。

protected DataSource determineTargetDataSource() {
    Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
    Object lookupKey = determineCurrentLookupKey();
    DataSource dataSource = this.resolvedDataSources.get(lookupKey);
    if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
        dataSource = this.resolvedDefaultDataSource;
    }
    if (dataSource == null) {
        throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
    }
    return dataSource;
}

  Object lookupKey = determineCurrentLookupKey(); 该方法是我们实现的,在其中获取ThreadLocal中保存的 key 值。(见上述步骤2)获得了key之后,在从afterPropertiesSet()(InitializingBean中实现的方法)中初始化好了的resolvedDataSources这个map中获得key对应的dataSource。而ThreadLocal中保存 key 值。

												

(七)spring+druid多数据源配置的更多相关文章

  1. Spring Druid多数据源配置

    SpringBoot 多数据源配置 如果需要在一个应用中使用多个数据源,应当如何实现呢,在Spring配置MyBatis中,我们可以看到以下的代码 <!-- mybatis 的SqlSessio ...

  2. Druid动态数据源配置

    上文已经讲了单个数据源的Druid的配置(http://www.cnblogs.com/nbfujx/p/7686634.html) Druid动态数据源配置 主要是继承AbstractRouting ...

  3. spring mysql多数据源配置

    spring mysql多数据源配置 @Configuration public class QuartzConfig { @Autowired private AutowireJobFactory ...

  4. Java spring mvc多数据源配置

    1.首先配置两个数据库<bean id="dataSourceA" class="org.apache.commons.dbcp.BasicDataSource&q ...

  5. Spring Boot多数据源配置(二)MongoDB

    在Spring Boot多数据源配置(一)durid.mysql.jpa 整合中已经讲过了Spring Boot如何配置mysql多数据源.本篇文章讲一下Spring Boot如何配置mongoDB多 ...

  6. Spring实现多数据源配置

    一.前言 对于小型项目,服务器与数据库是可以在同一台机子上的,但随着业务的庞大与负责,数据库和服务器就会分离开来.同时随着数据量的增大,数据库也要分开部署到多台机子上. 二.Spring配置文件修改 ...

  7. spring boot +mybatis+druid 多数据源配置

    因为我的工程需要在两个数据库中操作数据,所以要配置两个数据库,我这里没有数据源没有什么主从之分,只是配合多数据源必须要指定一个主数据源,所以我就把 操作相对要对的那个数据库设置为主数据(dataBas ...

  8. JAVA spring hibernate 多数据源配置记录

    数据源配置 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http:// ...

  9. spring boot(12)-数据源配置原理

    本篇讲的不仅是数据源配置,这也是spring boot实现自动配置的一部分.要理解数据源的配置原理,首先要理解第十篇tomcat连接池的配置 数据源配置源码 这里截取org.springframewo ...

随机推荐

  1. 1.pycharm使用

    太白金星的文档: https://www.cnblogs.com/jin-xin/articles/9811379.html 下载专业版,找破解码 一个python文件的开头如果有注视,必须是双引号的 ...

  2. gcc -c xx.c 选项讲解

    -c选项表示编译.汇编指定的源文件(也就是编译源文件),但是不进行链接.使用-c选项可以将每一个源文件编译成对应的目标文件. 目标文件是一种中间文件或者临时文件,如果不设置该选项,gcc 一般不会保留 ...

  3. goweb-文本处理

    文本处理 Web开发中对于文本处理是非常重要的一部分,我们往往需要对输出或者输入的内容进行处理,这里的文本包括字符串.数字.Json.XML等等.Go语言作为一门高性能的语言,对这些文本的处理都有官方 ...

  4. React 通过注释自动生成文档

    最近找了一些文档的生成工具,结果发现了这个 React Styleguidist 可以通过注释,自动生成对应的文档,对于 react 库来说十分方便 安装 npm i -D react-stylegu ...

  5. 计算KS值的标准代码

    计算KS值的标准代码 from scipy.stats import ks_2samp get_ks = lambda y_pred,y_true: ks_2samp(y_pred[y_true==1 ...

  6. 用最小的空间复杂度找出一个长度为n的数组且数据中的元素是[0,n-1]中任一个重复的数据。

    用最小的空间复杂度找出一个长度为n的数组且数据中的元素是[0,n-1]中任一个重复的数据. 比如:[1, 2, 3, 3, 2, 2, 6, 7, 8, 9] 中 2 or 3 分析:这道题目,实现比 ...

  7. PictureService

    package me.zhengjie.tools.service; import me.zhengjie.tools.domain.Picture; import org.springframewo ...

  8. 吴裕雄--天生自然python学习笔记:python 文件批量查找

    在多个文本文件中查找 我们首先来学习文本文件的查找字符 . 我们通过 os.walk 扩大查找范围, 查找指定目录和子目录下的文件. 应用程序总览 读取 当 前目录及子目录下的所有 PY 和 txt ...

  9. 怎么保证RabbitMQ和kafuka集群的高可用性?

    rabbitMQ有三种模式:单机模式,普通集群模式,镜像集群模式 RabbitMQ的高可用性   RabbitMQ是比较有代表性的,因为是基于主从做高可用性的,我们就以他为例子讲解第一种MQ的高可用性 ...

  10. 引入插件的时候 提示particlesJS is not defined

    particlesJS is not defined   插件或者js文件在引入时需要注意引入顺序,每次都找很久的错误 一般引入min.js就可以,min.js意思就是压缩的js文件 引入时应该先加入 ...