使用Spring配置动态数据源实现读写分离
最近搭建的一个项目需要实现数据源的读写分离,在这里将代码进行分享,以供参考。
关键词:DataSource 、AbstractRoutingDataSource、AOP
首先是配置数据源
<!--读数据源配置-->
<bean id="readDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"destroy-method="close">
//配置省略
</bean>
<!--写数据源配置-->
<bean id="writeDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"destroy-method="close">
//配置省略
</bean>
<!-- 动态数据源 -->
<bean id = "dataSource" class="com.potato.common.bean.DynamicDataSource" >
<!-- 已配置的数据源 -->
<property name="targetDataSources">
<map>
<entry key="READ" value-ref="readDataSource"/>
<entry key="WRITE" value-ref="writeDataSource"/>
</map>
</property>
<!-- 默认的数据源 -->
<property name="defaultTargetDataSource" ref="writeDataSource"/>
</bean>
数据源是如何切换的呢?通过动态数据源的配置我们知道原来是通过key来进行切换,这里要使用到org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource
,我们可以编写自己的动态数据源类DynamicDataSource
来继承它。
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getType();
}
}
还需要一个存放key的地方DataSourceContextHolder
为保证切换时线程安全我们使用ThreadLocal
来保存我们的key。
public class DataSourceContextHolder {
private static final Logger LOGGER = LoggerFactory.getLogger(DataSourceContextHolder.class);
public static final String DATA_SOURCE_WRITE = "WRITE";
public static final String DATA_SOURCE_READ = "READ";
// 线程本地环境
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
// 设置数据源类型
public static void setType(String type) {
if(LOGGER.isDebugEnabled())
LOGGER.debug("==============切换数据源,类型:"+type+"================");
contextHolder.set(type);
}
// 获取数据源类型
public static String getType() {
return (contextHolder.get());
}
// 清除数据源类型
public static void clearType() {
contextHolder.remove();
}
}
好了,我们可以通过操作DataSourceContextHolder
来实现数据源动态的切换了。小伙伴们可能会说了,难道每次调用方法都要手动选择要切换的数据源类型?当然不是啦,Spring AOP登场。
@Component
@Aspect
public class DynamicDataSourceAspect {
@Pointcut("execution (* com.potato.orm.mapper.*.select*(..)) || execution (* com.potato.orm.mapper.*.count*(..)) ")
public void readMethodPointcut() {}
@Pointcut("execution (* com.potato.orm.mapper.*.insert*(..)) || execution (* com.potato.orm.mapper.*.update*(..)) || execution (* com.potato.orm.mapper.*.delete*(..))")
public void writeMethodPointcut() {}
@Before("readMethodPointcut()")
public void switchReadDataSource(){
//System.out.println("============切换到读数据源===========");
DataSourceContextHolder.setType(DataSourceContextHolder.DATA_SOURCE_READ);
}
@Before("writeMethodPointcut()")
public void switchWriteDataSource(){
//System.out.println("=============切换到写数据源==========");
DataSourceContextHolder.setType(DataSourceContextHolder.DATA_SOURCE_WRITE);
}
}
好啦,在访问Mapper(本项目使用的是MyBatis啦,相当于是DAO)中查询
方法时会切换到读数据源,增、删、改
方法会切换到写数据源。
使用Spring配置动态数据源实现读写分离的更多相关文章
- 阿里P7教你如何使用 Spring 配置动态数据源实现读写分离
最近搭建的一个项目需要实现数据源的读写分离,在这里将代码进行分享,以供参考. 关键词:DataSource .AbstractRoutingDataSource.AOP 首先是配置数据源 <!- ...
- 使用 Spring 配置动态数据源实现读写分离
关键词:DataSource .AbstractRoutingDataSource.AOP 首先是配置数据源 <!--读数据源配置--><bean id="readData ...
- mybatis用spring的动态数据源实现读写分离
一.环境: 三个mysql数据库.一个master,两个slaver.master写数据,slaver读数据. 二.原理: 借助Spring的 AbstractRoutingDataSource 这个 ...
- spring 配置双数据源并读写分离
摘自 开源项目Ibase4j 关键思想在于AbstractRoutingSource 类 还有方法名称和切入点去控制使用哪个数据源 1.首先在配置文件配置多个数据源 并且交给继承自spri ...
- Spring配置动态数据源-读写分离和多数据源
在现在互联网系统中,随着用户量的增长,单数据源通常无法满足系统的负载要求.因此为了解决用户量增长带来的压力,在数据库层面会采用读写分离技术和数据库拆分等技术.读写分离就是就是一个Master数据库,多 ...
- 原理解密 → Spring AOP 实现动态数据源(读写分离),底层原理是什么
开心一刻 女孩睡醒玩手机,收到男孩发来一条信息:我要去跟我喜欢的人表白了! 女孩的心猛的一痛,回了条信息:去吧,祝你好运! 男孩回了句:但是我没有勇气说不来,怕被打! 女孩:没事的,我相信你!此时女孩 ...
- Spring动态数据源实现读写分离
一.创建基于ThreadLocal的动态数据源容器,保证数据源的线程安全性 package com.bounter.mybatis.extension; /** * 基于ThreadLocal实现的动 ...
- Spring Boot2(四):使用Spring Boot多数据源实现读写分离
前言 实际业务场景中,不可能只有一个库,所以就有了分库分表,多数据源的出现.实现了读写分离,主库负责增改删,从库负责查询.这篇文章将实现Spring Boot如何实现多数据源,动态数据源切换,读写分离 ...
- Spring实现动态数据源,支持动态加入、删除和设置权重及读写分离
当项目慢慢变大,訪问量也慢慢变大的时候.就难免的要使用多个数据源和设置读写分离了. 在开题之前先说明下,由于项目多是使用Spring,因此下面说到某些操作可能会依赖于Spring. 在我经历过的项目中 ...
随机推荐
- ORACLE常用函数汇总【转】
PL/SQL单行函数和组函数详解 函数是一种有零个或多个参数并且有一个返回值的程序.在SQL中Oracle内建了一系列函数,这些函数都可被称为SQL或PL/SQL语句, 函数主要分为两大类: 单行函数 ...
- sklearn包学习
1首先是sklearn的官网:http://scikit-learn.org/stable/ 在官网网址上可以看到很多的demo,下边这张是一张非常有用的流程图,在这个流程图中,可以根据数据集的特征, ...
- python基础---->python的使用(六)
这里记录一下python中关于class类的一些知识.不解释就弄不懂的事,就意味着怎样解释也弄不懂. python中的类知识 一.class的属性引用与实例 class MyClass(): '''A ...
- CF 455A Boredom
A. Boredom time limit per test 1 second memory limit per test 256 megabytes input standard input out ...
- GitStack系统RCE漏洞学习
漏洞简介 漏洞简情 漏洞程序 GitStack 影响版本 <=2.3.10 漏洞类型 RCE 漏洞评价 高危 漏洞编号 CVE-2018-5955 漏洞程序介绍 GitStack是一款基于Pyt ...
- Docker 容器管理:rancher
Rancher:https://www.cnrancher.com/ 是一个开源的企业级全栈化容器部署及管理平台. 定位上和 K8s 比较接近,都是通过 web 界面赋予完全的 docker 服务编排 ...
- DXP 内电层分割
多层电路板中间层设置与内电层如何分割 多层电路板与一般的电路板不同之处在于,多层电路板除了顶层和底层之外,还有若干中间层,这些中间层可以是信号层(mid layer),也可以是内部电源/接地层(int ...
- 在linux上执行.net Console apps
有个程序,在.net下写了半天,总算跑起来了,发现有个问题,在windows上不好弄,而同事前一段时间已经有Linux下的解决方法了,于是想直接将.net程序放在linux下运行 在linux上的mo ...
- 【BZOJ1814】Ural 1519 Formula 1 插头DP
[BZOJ1814]Ural 1519 Formula 1 题意:一个 m * n 的棋盘,有的格子存在障碍,求经过所有非障碍格子的哈密顿回路个数.(n,m<=12) 题解:插头DP板子题,刷板 ...
- Android aapt使用小结
Android打包成Apk后,其实是一个压缩文件,我们用winrar打开也能看到里面的文件结构.还能看到AndroidManifest.但是里面的内容有点问题. 不知道是因为加密还是Android就是 ...