摘自 开源项目Ibase4j

   关键思想在于AbstractRoutingSource 类 还有方法名称和切入点去控制使用哪个数据源

   1.首先在配置文件配置多个数据源 并且交给继承自spring AbstractRoutingSource去管理

datasource.xml配置如下

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
  6. http://www.springframework.org/schema/context
  7. http://www.springframework.org/schema/context/spring-context-4.0.xsd">
  8. <bean id="stat-filter" class="com.alibaba.druid.filter.stat.StatFilter" lazy-init="true">
  9. <description>状态过滤器</description>
  10. <property name="slowSqlMillis" value="3000" />
  11. <property name="logSlowSql" value="true" />
  12. <property name="mergeSql" value="true" />
  13. </bean>
  14. <bean id="readDataSource" class="com.alibaba.druid.pool.DruidDataSource"
  15. destroy-method="close" init-method="init" lazy-init="true">
  16. <description>只读数据库连接</description>
  17. <property name="driverClassName" value="${db.driver}" />
  18. <property name="url" value="${db.reader.url}" />
  19. <property name="username" value="${db.reader.username}" />
  20. <property name="password" value="${db.reader.password}" />
  21. <!-- 初始化连接大小 -->
  22. <property name="initialSize" value="${db.initialSize}" />
  23. <!-- 连接池最大数量 -->
  24. <property name="maxActive" value="${db.maxActive}" />
  25. <!-- 连接池最小空闲 -->
  26. <property name="minIdle" value="${db.minIdle}" />
  27. <!-- 获取连接最大等待时间 -->
  28. <property name="maxWait" value="${db.maxWait}" />
  29. <!-- -->
  30. <property name="defaultReadOnly" value="true" />
  31. <property name="proxyFilters">
  32. <list>
  33. <ref bean="stat-filter" />
  34. </list>
  35. </property>
  36. <property name="filters" value="${druid.filters}" />
  37. <property name="testWhileIdle" value="true" />
  38. <property name="testOnBorrow" value="false" />
  39. <property name="testOnReturn" value="false" />
  40. <property name="validationQuery" value="SELECT 'x'" />
  41. <property name="timeBetweenLogStatsMillis" value="60000" />
  42. <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
  43. <property name="minEvictableIdleTimeMillis" value="${db.minEvictableIdleTimeMillis}" />
  44. <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
  45. <property name="timeBetweenEvictionRunsMillis" value="${db.timeBetweenEvictionRunsMillis}" />
  46. </bean>
  47. <bean id="writeDataSource" class="com.alibaba.druid.pool.DruidDataSource"
  48. destroy-method="close" init-method="init" lazy-init="true">
  49. <description>只写数据库连接</description>
  50. <property name="driverClassName" value="${db.driver}" />
  51. <property name="url" value="${db.writer.url}" />
  52. <property name="username" value="${db.writer.username}" />
  53. <property name="password" value="${db.writer.password}" />
  54. <property name="initialSize" value="${db.initialSize}" />
  55. <property name="maxActive" value="${db.maxActive}" />
  56. <property name="minIdle" value="${db.minIdle}" />
  57. <property name="maxWait" value="${db.maxWait}" />
  58. <property name="defaultReadOnly" value="false" />
  59. <property name="proxyFilters">
  60. <list>
  61. <ref bean="stat-filter" />
  62. </list>
  63. </property>
  64. <property name="filters" value="${druid.filters}" />
  65. <property name="testWhileIdle" value="true" />
  66. <property name="testOnBorrow" value="false" />
  67. <property name="testOnReturn" value="false" />
  68. <property name="validationQuery" value="SELECT 'x'" />
  69. <property name="timeBetweenLogStatsMillis" value="60000" />
  70. <property name="minEvictableIdleTimeMillis" value="${db.minEvictableIdleTimeMillis}" />
  71. <property name="timeBetweenEvictionRunsMillis" value="${db.timeBetweenEvictionRunsMillis}" />
  72. </bean>
    <!--注意这里的配置-->
  73. <bean id="dataSource" class="org.ibase4j.core.aspect.ChooseDataSource" lazy-init="true">
  74. <description>数据源</description>
  75. <property name="targetDataSources">
  76. <map key-type="java.lang.String" value-type="javax.sql.DataSource">
  77. <!-- write -->
  78. <entry key="write" value-ref="writeDataSource" />
  79. <!-- read -->
  80. <entry key="read" value-ref="readDataSource" />
  81. </map>
  82. </property>
  83. <property name="defaultTargetDataSource" ref="writeDataSource" />
  84. <property name="methodType">
  85. <map key-type="java.lang.String">
  86. <!-- read -->
  87. <entry key="read" value=",get,select,count,list,query," />
  88. <!-- write -->
  89. <entry key="write" value=",add,insert,create,update,delete,remove," />
  90. </map>
  91. </property>
  92. </bean>
  93. <!-- 注意这个切面 -->
  94. <bean class="org.ibase4j.core.aspect.DataSourceAspect" />
  95. <!-- -->
  96. <bean class="org.springframework.jdbc.core.JdbcTemplate">
  97. <constructor-arg ref="dataSource" />
  98. </bean>
  99. </beans>

接下来事继承类

  1. package org.ibase4j.core.aspect;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.HashMap;
  5. import java.util.List;
  6. import java.util.Map;
  7.  
  8. import org.apache.commons.lang3.StringUtils;
  9. import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
  10.  
  11. /**
  12. * 获取数据源
  13. *
  14. * @author ShenHuaJie
  15. * @version 2016年5月20日 下午3:17:16
  16. */
  17. public class ChooseDataSource extends AbstractRoutingDataSource {
  18. public static Map<String, List<String>> METHODTYPE = new HashMap<String, List<String>>();
  19.  
  20. // 获取数据源名称
  21. protected Object determineCurrentLookupKey() {
  22. return HandleDataSource.getDataSource();
  23. }
  24.  
  25. // 设置方法名前缀对应的数据源
  26. public void setMethodType(Map<String, String> map) {
  27. for (String key : map.keySet()) {
  28. List<String> v = new ArrayList<String>();
  29. String[] types = map.get(key).split(",");
  30. for (String type : types) {
  31. if (StringUtils.isNotBlank(type)) {
  32. v.add(type);
  33. }
  34. }
  35. METHODTYPE.put(key, v);
  36. }
  37. }
  38. }

接下来切面实现类

  1. package org.ibase4j.core.aspect;
  2.  
  3. import org.apache.commons.lang3.StringUtils;
  4. import org.apache.logging.log4j.LogManager;
  5. import org.apache.logging.log4j.Logger;
  6. import org.aspectj.lang.JoinPoint;
  7. import org.aspectj.lang.annotation.After;
  8. import org.aspectj.lang.annotation.Aspect;
  9. import org.aspectj.lang.annotation.Before;
  10. import org.aspectj.lang.annotation.Pointcut;
  11. import org.springframework.context.annotation.EnableAspectJAutoProxy;
  12.  
  13. /**
  14. * 切换数据源(不同方法调用不同数据源)
  15. *
  16. * @author ShenHuaJie
  17. * @version 2016年5月20日 下午3:17:52
  18. */
  19. @Aspect
  20. @EnableAspectJAutoProxy(proxyTargetClass = true)
  21. public class DataSourceAspect {
  22. private final Logger logger = LogManager.getLogger();
  23. //配置切入点
  24. @Pointcut("execution(* org.ibase4j.service..*.*(..))")
  25. public void aspect() {
  26. }
  27.  
  28. /**
  29. * 配置前置通知,使用在方法aspect()上注册的切入点
  30. */
  31. @Before("aspect()")
  32. public void before(JoinPoint point) {
  33. String className = point.getTarget().getClass().getName();
  34. String method = point.getSignature().getName();
  35. logger.info(className + "." + method + "(" + StringUtils.join(point.getArgs(), ",") + ")");
  36. try {
  37. L: for (String key : ChooseDataSource.METHODTYPE.keySet()) {
  38. for (String type : ChooseDataSource.METHODTYPE.get(key)) {
  39. if (method.startsWith(type)) {
  40. logger.info(key);
  41. HandleDataSource.putDataSource(key);
  42. break L;
  43. }
  44. }
  45. }
  46. } catch (Exception e) {
  47. logger.error(e);
  48. HandleDataSource.putDataSource("write");
  49. }
  50. }
  51.  
  52. @After("aspect()")
  53. public void after(JoinPoint point) {
  54. HandleDataSource.clear();
  55. }
  56. }

还有一个帮助你拿到数据元的类

  1. package org.ibase4j.core.aspect;
  2.  
  3. /**
  4. * @author ShenHuaJie
  5. * @version 2016年5月20日 下午3:18:04
  6. */
  7. public class HandleDataSource {
  8. // 数据源名称线程池
  9. private static final ThreadLocal<String> holder = new ThreadLocal<String>();
  10.  
  11. public static void putDataSource(String datasource) {
  12. holder.set(datasource);
  13. }
  14.  
  15. public static String getDataSource() {
  16. return holder.get();
  17. }
  18.  
  19. public static void clear() {
  20. holder.remove();
  21. }
  22. }

spring 配置双数据源并读写分离的更多相关文章

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

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

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

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

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

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

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

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

  5. Spring Boot2(四):使用Spring Boot多数据源实现读写分离

    前言 实际业务场景中,不可能只有一个库,所以就有了分库分表,多数据源的出现.实现了读写分离,主库负责增改删,从库负责查询.这篇文章将实现Spring Boot如何实现多数据源,动态数据源切换,读写分离 ...

  6. spring项目配置双数据源读写分离

    我们最早做新项目的时候一直想做数据库的读写分离与主从同步,由于一些原因一直没有去做这个事情,这次我们需要配置双数据源的起因是因为我们做了一个新项目用了另一个数据库,需要把这个数据库的数据显示到原来的后 ...

  7. Spring配置动态数据源-读写分离和多数据源

    在现在互联网系统中,随着用户量的增长,单数据源通常无法满足系统的负载要求.因此为了解决用户量增长带来的压力,在数据库层面会采用读写分离技术和数据库拆分等技术.读写分离就是就是一个Master数据库,多 ...

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

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

  9. 170301、使用Spring AOP实现MySQL数据库读写分离案例分析

    使用Spring AOP实现MySQL数据库读写分离案例分析 原创 2016-12-29 徐刘根 Java后端技术 一.前言 分布式环境下数据库的读写分离策略是解决数据库读写性能瓶颈的一个关键解决方案 ...

随机推荐

  1. OkHttp之BridgeInterceptor简单分析

    在< Okhttp源码简单解析(一) >这篇博客简单分析了Okhttp请求的执行流程,通过该篇博客我们知道OkHttp的核心网络请求中内置"拦截器"发挥了重大作用:本篇 ...

  2. 深度学习(六十七)metal forge深度学习库使用

    1.设置输入: let input = Input() 或者 let input = Input(width: 100, height: 100, channels: 3) 2.创建网络: let o ...

  3. Shell 批量搜索关键词并保存结果到文件中(数组、循环)

    #!/bin/bash keywords=("不需要" "不用谢谢" "xxx" "xxx") for var in $ ...

  4. spring boot入门教程——Spring Boot快速入门指南

    Spring Boot已成为当今最流行的微服务开发框架,本文是如何使用Spring Boot快速开始Web微服务开发的指南,我们将使创建一个可运行的包含内嵌Web容器(默认使用的是Tomcat)的可运 ...

  5. android代码常识

    查看当前android代码版本号:build/core/version_defaults.mk---->查找platform_version android源码在线阅读网址 http://and ...

  6. vue中如何引入全局样式或方法

    vue中我么会经常用到通用的一些全局的方法,如何左才能实现全局的复用减少代码累赘呢? 我们一般将公用的方法分装再utils.js文件中,然后再main.js主入口文件中将utils.js中的公共的方法 ...

  7. maven创建多模块项目

    在eclipse下构建maven项目,该项目由多个子模块组成. 1.创建一个父项目 NEW -->project-->maven-->maven Project,点击下一步,进入ne ...

  8. Sprint第一个冲刺(第二天)

    一.Sprint介绍 今天我们完成了欢迎界面及美化的任务,即完成了此次整个Sprint的百分之七,登录界面及美化.注册界面(管理员).注册界面(餐厅员工)和注册界面(消费者),这几个任务也在进行时.这 ...

  9. 转:Excel导入SQL数据库完整代码

    Excel导入SQL数据库完整代码 protected void studentload_Click(object sender, EventArgs e) {//批量添加学生信息 SqlConnec ...

  10. python: find the index of a given value in a list

    ["foo", "bar", "baz"].index("bar")