需求

代码实现读写数据库分离

武器

spring3.0以上版本

实现思路

1、继承org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource,自定义数据源路由。

2、实现数据源类型管理工具,诸如DBContextHolder,包含设置和读取当前数据源配置。

3、实现数据源切换的AOP。

4、自定义只读注解,诸如@ReadOnlyKey。

5、配置transactionManager,实现aop。

代码示例

1、自定义的DynamicDataSource

public class DynamicDataSource extends AbstractRoutingDataSource {
/**
* 自动查找数据源
*
* @return 数据源名
*/
@Override
protected Object determineCurrentLookupKey() {
String dataSource = getDataSource();
return dataSource;
}
}

2、数据源类型管理工具DBContextHolder

public abstract class DBContextHolder {
/**
* 数据源类型管理
* <p>
* 考虑多线程,为保证线程之间互不干扰,所以使用ThreadLocal作线程隔离;<br>
* 参数是数据源键值
* </p>
*
* @see ThreadLocal
*/
private static ThreadLocal<String> contextHolder = new ThreadLocal<String>(); /**
* 数据库源类型
* <p>
* 配置数据源的时候,请遵守以下约束:<br>
* 读写:dataSourceKeyRW;<br>
* 读:dataSourceKeyR.
* </p>
*/
public enum DbType {
DB_TYPE_RW("dataSourceKeyRW"), DB_TYPE_R("dataSourceKeyR");
private String dataSourceKey; DbType(String dataSourceKey) {
this.dataSourceKey = dataSourceKey;
} public String getDataSourceKey() {
return dataSourceKey;
}
} /**
* 获取数据源
* <p>
* 如果未设置,默认返回读数据源
* </p>
*
* @return 数据源键值
*/
public static String getDataSource() {
String dataSource = contextHolder.get();
if (StringUtils.isEmpty(dataSource)) {
dataSource = DbType.DB_TYPE_RW.dataSourceKey;
}
return dataSource;
} /**
* 设置数据源
*
* @param dataSourceKey 数据源键值
*/
public static void setDataSource(String dataSourceKey) {
contextHolder.set(dataSourceKey);
}
}

注:定义了DbType枚举,分别定义了读和写的数据源键值。

3、实现AOP。

public class DataSourceSwitchingAop {
/**
* 设置切点数据源
* <p>
* 调试输出数据源.
* </p>
*
* @param joinPoint 切点
* @param dataSourceKey 当前数据源键值
*/
private void setDataSourceByKey(JoinPoint joinPoint, String dataSourceKey) {
setDataSource(dataSourceKey);
debugLog(joinPoint.getTarget().getClass().getSimpleName() + "." + joinPoint.getSignature().getName() + "配置数据源:" + getDataSource());
} /**
* 切换数据源
* <p>
* 切换优先级由高到底如下;方法上注解DataSourceKey,方法上注解ReadOnlyKey,类上注解DataSourceKey;<br>
* 如果未注解,则默认设置写数据源.
* </p>
*
* @param joinPoint 切点
* @see DataSourceKey
* @see ReadOnlyKey
* @see DbType
*/
public void switchDataSource(JoinPoint joinPoint) {
Class<?> targetClass = joinPoint.getTarget().getClass();
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
DataSourceKey dataSourceKey = getAnnotationClassMethod(targetClass, methodName, DataSourceKey.class, args);
if (dataSourceKey != null) {
setDataSourceByKey(joinPoint, dataSourceKey.dataSourceKey());
return;
}
ReadOnlyKey readOnlyKey = getAnnotationClassMethod(targetClass, methodName, ReadOnlyKey.class, args);
if (readOnlyKey != null) {
setDataSourceByKey(joinPoint, DbType.DB_TYPE_R.getDataSourceKey());
return;
}
dataSourceKey = (DataSourceKey) targetClass.getAnnotation(DataSourceKey.class);
if (dataSourceKey != null) {
setDataSourceByKey(joinPoint, dataSourceKey.dataSourceKey());
return;
}
setDataSourceByKey(joinPoint, DbType.DB_TYPE_RW.getDataSourceKey());
}
}

4、自定义只读注解,@ReadOnlyKey

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ReadOnlyKey {
}

5、配置transaction和AOP

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dynamicDataSource"/>
</bean>
<bean id="dataSourceSwitchingAop" class="com.xxx.common.framework2x.dao.DataSourceSwitchingAop"/>
<aop:config>
<aop:aspect id="dataSourceSwitching" ref="dataSourceSwitchingAop" order="0">
<aop:pointcut id="dataSourceSwitchingService"
expression="execution(* com.xxx.manager..*.*(..))"/>
<aop:before method="switchDataSource" pointcut-ref="dataSourceSwitchingService"/>
</aop:aspect>
</aop:config>

以上就完成了基于注解实现动态切换读写数据源。

6、如果想要实现多数据源的切换,则可以自定义注解@DataSourceKey

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface DataSourceKey {
/**
* 配置数据源键值
* <p>
* 默认:dataSource.
* </p>
*
* @return 键值
*/
String dataSourceKey() default "dataSource";
}

在接口方法上增加注解即可。

需要特别注意的地方

1、切换数据源的事务需要放到数据库事务开启前执行。针对上述代码示例中,配置aop时需要指定order(值越小,执行越靠前)

<aop:config>
<aop:aspect id="dataSourceSwitching" ref="dataSourceSwitchingAop" order="0">
<aop:pointcut id="dataSourceSwitchingService"
expression="execution(* com.xxx.manager..*.*(..))"/>
<aop:before method="switchDataSource" pointcut-ref="dataSourceSwitchingService"/>
</aop:aspect>
</aop:config>

2、@DataSourceKey可以加在method上,也可以加到class上,优先级是method>class。

3、@ReadOnlyKey只能加到method上。

4、@DatasourceKey和@ReadOnlyKey可以在一个class中混用,优先级是method的@DatasourceKey>method的@ReadOnlyKey>class的@DatasourceKey。

springAOP实现基于注解的数据源动态切换的更多相关文章

  1. SPRINGAOP实现基于注解的数据源动态切换(转)

    需求 代码实现读写数据库分离 武器 spring3.0以上版本 实现思路 1.继承org.springframework.jdbc.datasource.lookup.AbstractRoutingD ...

  2. Spring3.3 整合 Hibernate3、MyBatis3.2 配置多数据源/动态切换数据源 方法

    一.开篇 这里整合分别采用了Hibernate和MyBatis两大持久层框架,Hibernate主要完成增删改功能和一些单一的对象查询功能,MyBatis主要负责查询功能.所以在出来数据库方言的时候基 ...

  3. Springboot多数据源配置--数据源动态切换

    在上一篇我们介绍了多数据源,但是我们会发现在实际中我们很少直接获取数据源对象进行操作,我们常用的是jdbcTemplate或者是jpa进行操作数据库.那么这一节我们将要介绍怎么进行多数据源动态切换.添 ...

  4. springboot多数据源动态切换和自定义mybatis分页插件

    1.配置多数据源 增加druid依赖 完整pom文件 数据源配置文件 route.datasource.driver-class-name= com.mysql.jdbc.Driver route.d ...

  5. Spring3.3 整合 Hibernate3、MyBatis3.2 配置多数据源/动态切换数据源方法

    一.开篇 这里整合分别采用了Hibernate和MyBatis两大持久层框架,Hibernate主要完成增删改功能和一些单一的对象查询功能,MyBatis主要负责查询功能.所以在出来数据库方言的时候基 ...

  6. Spring多数据源动态切换

    title: Spring多数据源动态切换 date: 2019-11-27 categories: Java Spring tags: 数据源 typora-root-url: ...... --- ...

  7. mybatis 多数据源动态切换

    笔者主要从事c#开发,近期因为项目需要,搭建了一套spring-cloud微服务框架,集成了eureka服务注册中心. gateway网关过滤.admin服务监控.auth授权体系验证,集成了redi ...

  8. 实战:Spring AOP实现多数据源动态切换

    需求背景 去年底,公司项目有一个需求中有个接口需要用到平台.算法.大数据等三个不同数据库的数据进行计算.组装以及最后的展示,当时这个需求是另一个老同事在做,我只是负责自己的部分. 直到今年回来了,这个 ...

  9. 基于注解实现jackson动态JsonProperty

    基于注解实现jackson动态JsonProperty @JsonProperty 此注解用于属性上,作用是把该属性的名称序列化为另外一个名称,如把trueName属性序列化为name,但是值是固定的 ...

随机推荐

  1. 如何将Console application的Program函数变成支持async的?

    如何将Console application的Program函数变成支持async的?   class Program { static void Main(string[] args) { Task ...

  2. 在Android中自定义捕获Application全局异常,可以替换掉系统的强制退出对话框(很有参考价值与实用价值)

    转载自: http://blog.csdn.net/jdsjlzx/article/details/7606423

  3. cookie 和session 的区别

    假如我填好了淘宝的用户名密码,点击登录,浏览器客户端像服务器端发送请求,这时服务器端看这个用户是第一次登陆,session会让客户端这个浏览器生成个cookie,并给cookie一个session i ...

  4. Canvas画图在360浏览器中跑偏的问题

    问题描述,canvas画图的js代码中编写的是画正方形的代码,结果在360浏览器上变成了长方形,不知道怎么回事,请问各位大神是否遇到过此类问题? <!DOCTYPE html> <h ...

  5. 2016 ICPC China-Final 现场赛总结

    距离比赛结束快有一个礼拜了才抽出时间来写这篇总结.今年比赛打了也有5场了(4场区域赛+1场省赛),也取得了不错的成绩(区域赛两银),总的来说第一年就取得这成绩还是挺高兴的.我们队,我自己都渐渐的趋于成 ...

  6. Linux性能工具介绍

    l  Linux性能工具介绍 p  CPU高 p  磁盘I/O p  网络 p  内存 p  应用程序跟踪 l  操作系统与应用程序的关系比喻为“唇亡齿寒”一点不为过 l  应用程序的性能问题/功能问 ...

  7. jdk环境变量的配置并检测是否配置成功

    JDK环境变量配置进行java开发,首先安装JDK,安装后进行环境变量配置1,下载JDK(http://java.sun.com/javase/downloads/index.jsp)2.安装jdk- ...

  8. fedora23 tweak tool不工作解决方案

    在启动器中打开 优化工具 失败 在终端中开启显示 Traceback (most recent call last): File "/usr/bin/gnome-tweak-tool&quo ...

  9. dp与px转换

    名词 解释 Px (Pixel像素) 不同设备显示效果相同.这里的“相同”是指像素数不会变,比如指定UI长度是100px,那不管分辨率是多少UI长度都是100px.也正是因为如此才造成了UI在小分辨率 ...

  10. VMware Workstation+Linux+Xshell+Xftp+MySQL+SQLyog 配置

    这些天在搞这些个东西做项目,配置较繁,这里记下安装过程中的要点. 1.VMware Workstation 主要是 NAT 方式联网的问题,详述如下,来自网络. NAT 配置那里注意网关,虚拟机中网关 ...