spring与druid可以实现动态数据源,夸库查询,读写分离等功能。现在说一下配置:

1、需要配置多个spring数据源

spring-data.xml

<!-- 动态数据源 -->
<bean id="dynamicDataSource" class="com.myproject.common.db.util.DynamicDataSource">
<!-- 通过key-value关联数据源 -->
<property name="targetDataSources">
<map>
<entry value-ref="dataSourceWrite" key="dataSourceWrite"></entry>
<entry value-ref="dataSourceRead" key="dataSourceRead"></entry>
</map>
</property>
<property name="defaultTargetDataSource" ref="dataSourceWrite" />
</bean> <!--mybatis与Spring整合 -->
<bean id="sqlSessionFactory" name="sqlSessionFactory"
class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis.xml"></property>
<property name="mapperLocations" value="classpath*:mapper/*.xml" />
<property name="dataSource" ref="dynamicDataSource" />
</bean> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
</bean> <bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dynamicDataSource" />
</bean> <tx:annotation-driven transaction-manager="transactionManager" /> <!-- 数据源(DruidDataSource) -->
<bean id="dataSourceWrite" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<property name="url" value="${urlOracle}" />
<property name="username" value="${usernameOracle}" />
<property name="password" value="${passwordOracle}" />
<!-- 初始化连接大小 -->
<property name="initialSize" value="5" />
<!-- 连接池最大使用连接数量 -->
<property name="maxActive" value="200" />
<!-- 连接池最小空闲 -->
<property name="minIdle" value="5" />
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="60000" />
<!-- <property name="poolPreparedStatements" value="true" /> <property
name="maxPoolPreparedStatementPerConnectionSize" value="33" /> -->
<!-- <property name="validationQuery" value="${jdbc.validationQuery}" /> -->
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
<property name="testWhileIdle" value="true" />
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="25200000" />
<!-- 打开removeAbandoned功能 -->
<property name="removeAbandoned" value="true" />
<!-- 1800秒,也就是30分钟 -->
<property name="removeAbandonedTimeout" value="1800" />
<!-- 关闭abanded连接时输出错误日志 -->
<property name="logAbandoned" value="true" />
<!-- 监控数据库 -->
<!-- <property name="filters" value="mergeStat" /> -->
<property name="filters" value="stat" />
<property name="defaultAutoCommit" value="true" />
</bean> <bean id="dataSourceRead" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<property name="url" value="${urlMysql}" />
<property name="username" value="${usernameMysql}" />
<property name="password" value="${passwordMysql}" />
<!-- 初始化连接大小 -->
<property name="initialSize" value="5" />
<!-- 连接池最大使用连接数量 -->
<property name="maxActive" value="200" />
<!-- 连接池最小空闲 -->
<property name="minIdle" value="5" />
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="60000" />
<!-- <property name="poolPreparedStatements" value="true" /> <property
name="maxPoolPreparedStatementPerConnectionSize" value="33" /> -->
<!-- <property name="validationQuery" value="${jdbc.validationQuery}" /> -->
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
<property name="testWhileIdle" value="true" />
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="25200000" />
<!-- 打开removeAbandoned功能 -->
<property name="removeAbandoned" value="true" />
<!-- 1800秒,也就是30分钟 -->
<property name="removeAbandonedTimeout" value="1800" />
<!-- 关闭abanded连接时输出错误日志 -->
<property name="logAbandoned" value="true" />
<!-- 监控数据库 -->
<!-- <property name="filters" value="mergeStat" /> -->
<property name="filters" value="stat" />
<property name="defaultAutoCommit" value="true" />
</bean>

2、需要写一个DynamicDataSource类继承AbstractRoutingDataSource,并实现determineCurrentLookupKey方法

public class DynamicDataSource extends AbstractRoutingDataSource {  

    /**
*
* override determineCurrentLookupKey
* <p>
* Title: determineCurrentLookupKey
* </p>
* <p>
* Description: 自动查找datasource
* </p>
*
* @return
*/
@Override
protected Object determineCurrentLookupKey() {
return DBContextHolder.getDSType();
} }

3、参考spring事务管理,使用线程变量来切换数据源

public class DBContextHolder {

	/**
* 线程threadlocal
*/
private static ThreadLocal<String> contextHolder = new ThreadLocal<>();
private static Logger logger = LoggerFactory
.getLogger(DBContextHolder.class); public static String getDSType() {
try { } catch (Exception e) {
e.printStackTrace();
logger.error("get DBTYPE faild with error:[" + e.getMessage() + "]");
} String db = contextHolder.get();
if (db == null) {
db =UrlConnect.getKey(ConfigHelper.getToWriteKey());// 默认是读写库
}
return db;
} /**
*
* 设置本线程的dbtype
*
* @param str
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
public static boolean setDSType(String str) {
try {
clearDBType();
if (str != null&&!str.equals("")) {
contextHolder.set(str);
logger.info("change thread[" + str + "] success!");
return true;
} else {
logger.info("change thread[" + str + "] faild!");
return false;
}
} catch (Exception e) {
e.printStackTrace();
logger.error("change thread[" + str + "] faild!");
return false;
}
} /**
* clearDBType
*
* @Title: clearDBType
* @Description: 清理连接类型
*/
public static void clearDSType() {
contextHolder.remove();
}
}

4、在dao中切换数据源

@Repository
public class BaseDAO extends SqlSessionDaoSupport {
@Resource
private SqlSessionTemplate sqlSessionTemplate;
@Resource
public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
super.setSqlSessionTemplate(sqlSessionTemplate);
} public <T> PageList<T> selectPublicListPage(String countSqlID,String sqlID,
PageList<T> page, Object obj) {
DBContextHolder.setDbType("dataSourceRead");
//查询总数
Integer total = this.getSqlSession().selectOne(countSqlID, obj);
RowBounds rowBounds=new RowBounds(page.getFirstResult(),page.getPageSize());
// 查询列表信息
List<T> list = this.getSqlSession().selectList(
sqlID, obj,rowBounds);
page.setTotalRecord(total!=null?total:0);
page.setDataSource(list);
page.setTotalPage((total + page.getPageSize() - 1)
/ page.getPageSize());
return page;
} public int insert(String sqlID, Object paramObj) {
DBContextHolder.setDbType("dataSourceWrite");
return this.getSqlSession().insert(sqlID, paramObj);
} }

基于druid和spring的动态数据库以及读写分离 转的更多相关文章

  1. spring aop实现数据库的读写分离

    为了减轻数据库的压力,一般会使用数据库主从(master/slave)的方式,但是这种方式会给应用程序带来一定的麻烦,比如说,应用程序如何做到把数据写到master库,而读取数据的时候,从slave库 ...

  2. mybatis用spring的动态数据源实现读写分离

    一.环境: 三个mysql数据库.一个master,两个slaver.master写数据,slaver读数据. 二.原理: 借助Spring的 AbstractRoutingDataSource 这个 ...

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

    最近搭建的一个项目需要实现数据源的读写分离,在这里将代码进行分享,以供参考.关键词:DataSource .AbstractRoutingDataSource.AOP 首先是配置数据源 <!-- ...

  4. 阿里P7教你如何使用 Spring 配置动态数据源实现读写分离

    最近搭建的一个项目需要实现数据源的读写分离,在这里将代码进行分享,以供参考. 关键词:DataSource .AbstractRoutingDataSource.AOP 首先是配置数据源 <!- ...

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

    关键词:DataSource .AbstractRoutingDataSource.AOP 首先是配置数据源 <!--读数据源配置--><bean id="readData ...

  6. 基于 EntityFramework 的数据库主从读写分离架构(1) - 原理概述和基本功能实现

        回到目录,完整代码请查看(https://github.com/cjw0511/NDF.Infrastructure)中的目录:      src\ NDF.Data.EntityFramew ...

  7. 原理解密 → Spring AOP 实现动态数据源(读写分离),底层原理是什么

    开心一刻 女孩睡醒玩手机,收到男孩发来一条信息:我要去跟我喜欢的人表白了! 女孩的心猛的一痛,回了条信息:去吧,祝你好运! 男孩回了句:但是我没有勇气说不来,怕被打! 女孩:没事的,我相信你!此时女孩 ...

  8. 基于 EntityFramework 的数据库主从读写分离服务插件

    基于 EntityFramework 的数据库主从读写分离服务插件 1. 版本信息和源码 1.1 版本信息 v1.01 beta(2015-04-07),基于 EF 6.1 开发,支持 EF 6.1 ...

  9. 基于 EntityFramework 的数据库主从读写分离架构 - 目录

    基于 EntityFramework 的数据库主从读写分离架构       回到目录,完整代码请查看(https://github.com/cjw0511/NDF.Infrastructure)中的目 ...

  10. spring集成mybatis实现mysql读写分离

    前言 在网站的用户达到一定规模后,数据库因为负载压力过高而成为网站的瓶颈.幸运的是目前大部分的主流数据库都提供主从热备功能,通过配置两台数据库主从关系,可以将一台数据库的数据更新同步到另一台服务器上. ...

随机推荐

  1. python正则表达式替换所有内容并同时保留找到的内容

    除了一些专业的工具,例如ue,大部分编程语言的函数包都挺让人迷惑的,例如Java,js. 因为的确有许多功能是很常用的,但是他们又不提供,非得要程序员自己去实现,或者是利用三方的包. 到底是什么理由了 ...

  2. Freertos学习:04-任务的调试函数

    --- title: rtos-freertos-04-任务的调试函数 EntryName: rtos-freertos-04-task-debug date: 2020-06-22 08:49:06 ...

  3. 配置上新 | 单双四核任选,TI Cortex-A53工业核心板仅198元起!

    创龙科技作为TI官方合作伙伴,在2022年9月即推出搭载TI AM62x最新明星处理器的工业核心板-SOM-TL62x. SOM-TL62x工业核心板基于TI Sitara系列AM62x单/双/四核A ...

  4. 1.Javascript 快速入门(主要)

    运算 &&运算是与运算,只有所有都为true,&&运算结果才是true: true && true; // 这个&&语句计算结果为tru ...

  5. MQ和RabbitMQ

    一.微服务间通讯有同步和异步两种方式: 同步通讯:就像打电话,需要实时响应. 异步通讯:就像发邮件,不需要马上回复. Feign调用就属于同步方式,虽然调用可以实时得到结果,但存在下面的问题: 1.耦 ...

  6. Java-EL表达式替换和简化jsp页面中java代码的编写

    概念:Expression Language 表达式语言 作用:替换和简化jsp页面中java代码的编写 语法:$ 注意: jsp默认支持el表达式,如果要忽略el表达式 设置jsp中page指令中: ...

  7. CF1359A 题解

    洛谷链接&CF 链接 题目简述 共有 \(T\) 组数据. 对于每组数据给出 \(n,m,k\),表示 \(k\) 名玩家打牌,共 \(n\) 张牌,\(m\) 张王,保证 \(k \mid ...

  8. SMU Summer 2024 Contest Round 1(7.8)zhaosang

    A-A http://162.14.124.219/contest/1005/problem/A 一道数学问题,求概率. 要求成功的概率,有两个色子, 一个用来抛正反面,一个用来控制得分大小,当超过某 ...

  9. 如何查询MySQL存储的树形结构,层次结构

    表定义如下 如果我们需要在表中查询这个树状结构,通过SQL语句,有两种查询方法: 1.通过inner自连接查询,适用于简单的结构 SELECT * FROM course_category AS on ...

  10. 国内外GPT哪家强?对比#ChatGPT #bard #豆包 #bing #百度文心 #星火 #通义千问

    #ChatGPT(openAi) ChatGPT已经被错误调教,经常把作者和名字搞混. #豆包(字节跳动) 豆包拒绝错误调教 #百度文心(百度) #星火(科大讯飞) #通义千问 (阿里巴巴) #bar ...