基于druid和spring的动态数据库以及读写分离 转
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的动态数据库以及读写分离 转的更多相关文章
- spring aop实现数据库的读写分离
为了减轻数据库的压力,一般会使用数据库主从(master/slave)的方式,但是这种方式会给应用程序带来一定的麻烦,比如说,应用程序如何做到把数据写到master库,而读取数据的时候,从slave库 ...
- mybatis用spring的动态数据源实现读写分离
一.环境: 三个mysql数据库.一个master,两个slaver.master写数据,slaver读数据. 二.原理: 借助Spring的 AbstractRoutingDataSource 这个 ...
- 使用Spring配置动态数据源实现读写分离
最近搭建的一个项目需要实现数据源的读写分离,在这里将代码进行分享,以供参考.关键词:DataSource .AbstractRoutingDataSource.AOP 首先是配置数据源 <!-- ...
- 阿里P7教你如何使用 Spring 配置动态数据源实现读写分离
最近搭建的一个项目需要实现数据源的读写分离,在这里将代码进行分享,以供参考. 关键词:DataSource .AbstractRoutingDataSource.AOP 首先是配置数据源 <!- ...
- 使用 Spring 配置动态数据源实现读写分离
关键词:DataSource .AbstractRoutingDataSource.AOP 首先是配置数据源 <!--读数据源配置--><bean id="readData ...
- 基于 EntityFramework 的数据库主从读写分离架构(1) - 原理概述和基本功能实现
回到目录,完整代码请查看(https://github.com/cjw0511/NDF.Infrastructure)中的目录: src\ NDF.Data.EntityFramew ...
- 原理解密 → Spring AOP 实现动态数据源(读写分离),底层原理是什么
开心一刻 女孩睡醒玩手机,收到男孩发来一条信息:我要去跟我喜欢的人表白了! 女孩的心猛的一痛,回了条信息:去吧,祝你好运! 男孩回了句:但是我没有勇气说不来,怕被打! 女孩:没事的,我相信你!此时女孩 ...
- 基于 EntityFramework 的数据库主从读写分离服务插件
基于 EntityFramework 的数据库主从读写分离服务插件 1. 版本信息和源码 1.1 版本信息 v1.01 beta(2015-04-07),基于 EF 6.1 开发,支持 EF 6.1 ...
- 基于 EntityFramework 的数据库主从读写分离架构 - 目录
基于 EntityFramework 的数据库主从读写分离架构 回到目录,完整代码请查看(https://github.com/cjw0511/NDF.Infrastructure)中的目 ...
- spring集成mybatis实现mysql读写分离
前言 在网站的用户达到一定规模后,数据库因为负载压力过高而成为网站的瓶颈.幸运的是目前大部分的主流数据库都提供主从热备功能,通过配置两台数据库主从关系,可以将一台数据库的数据更新同步到另一台服务器上. ...
随机推荐
- Jupyter QtConsole 配置,2023 年了你还在使用 QtConsole 吗?
目录 Jupyter QtConsole 配置,2023 年了你还在使用 QtConsole 吗? Jupyter QtConsole 的安装 设置字体 启动时自动加载需要的库包 更新:2023 年 ...
- Mysql 使用(二)
1 启动: 2 net start mysql 3 4 进入: 5 mysql -uroot -pmysql 6 7 显示数据库: 8 show databases; 9 10 使用数据库: 11 u ...
- 10分钟掌握Python缓存
全文速览 python的不同缓存组件的使用场景和使用样例 cachetools的使用 项目背景 代码检查项目,需要存储每一步检查的中间结果,最终把结果汇总并写入文件中 在中间结果的存储中 可以使用co ...
- B 站和小红书又又又崩了,罪魁祸首竟然又是他。。。
大家好,我是凌晨. 今天上午10点左右,我打开B站发现无法刷新视频列表和评论区,收藏夹和弹幕也均不可用. 原以为是手机网络问题,换网络重启手机都还是不行,第一时间打开微博,果然,B站崩了的新闻荣登榜首 ...
- ELK日志缺失问题排查-多行日志聚合Logstash配置问题
1. 背景 推荐系统的推荐请求追踪日志,通过ELK收集,方便遇到问题时,可以通过唯一标识sid来复现推荐过程 最近在碰到了几个bad case,需要通过sid来查询推荐日志,但发现部分无法在kiban ...
- package-lock.json 文件
今天有同事找到我说,本地js 编译不过,编译不过的代码如下 const host = window?.location?.host || 'localhost'; 是option chaining, ...
- Spring 获取Bean ApplicationContextAware的使用
创建类继承ApplicationContextAware package net.ybclass.online_ybclass.utils; import org.springframework.be ...
- 如何优雅地使用Mybatis逆向工程生成类
文/朱季谦 1.环境:SpringBoot 2.在pom.xml文件里引入相关依赖: 1 <plugin> 2 <groupId>org.mybatis.generator&l ...
- 解决方案 | 一个VBA代码里面非常隐蔽的错误:运行时错误“5”:无效的过程调用或参数
1 代码部分 代码功能:实现使用sumatra打开指定pdf指定页码 代码: Sub OpenPDFatPage() Dim PDFFile As String Dim PageNumber As L ...
- 机器学习策略篇:详解处理数据不匹配问题(Addressing data mismatch)
处理数据不匹配问题 如果您的训练集来自和开发测试集不同的分布,如果错误分析显示有一个数据不匹配的问题该怎么办?这个问题没有完全系统的解决方案,但可以看看一些可以尝试的事情.如果发现有严重的数据不匹配问 ...