博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
未测试---- mysql+spring+mybatis实现数据库读写分离[代码配置]
阅读量:2352 次
发布时间:2019-05-10

本文共 5832 字,大约阅读时间需要 19 分钟。

文章来源:http://blog.csdn.net/xtj332/article/details/43953699

场景:一个读数据源一个读写数据源。

原理:借助spring的【org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource】这个抽象类实现,看名字可以了解到是一个路由数据源的东西,这个类中有一个方法

[java]
  1. /** 
  2.  * Determine the current lookup key. This will typically be 
  3.  * implemented to check a thread-bound transaction context. 
  4.  * <p>Allows for arbitrary keys. The returned key needs 
  5.  * to match the stored lookup key type, as resolved by the 
  6.  * {@link #resolveSpecifiedLookupKey} method. 
  7.  */  
  8. protected abstract Object determineCurrentLookupKey();  
每次去连数据库的时候,spring会调用这个方法去找对应的数据源。返回值即对应的数据源的LookUpKey.那么这个LookUpKey在哪定义的呢?看下面的dataBase.xml的配置

[html]
  1. <!--数据源 读写 -->  
  2. <bean id="dataSourceRW" class="org.logicalcobwebs.proxool.ProxoolDataSource">  
  3.     <property name="alias" value="ihotelRW"></property>  
  4.     <property name="delegateProperties">  
  5.         <value>user=${jdbc.username},password=${jdbc.password}  
  6.         </value>  
  7.     </property>  
  8.     <property name="user" value="${jdbc.username}" />  
  9.     <property name="password" value="${jdbc.password}" />  
  10.     <property name="driver" value="${jdbc.driverClassName}" />  
  11.     <property name="driverUrl" value="${jdbc.url}" />  
  12.     <property name="maximumConnectionCount" value="${jdbc.maximumConnectionCount}"></property>  
  13.     <property name="maximumActiveTime" value="${jdbc.maximumActiveTime}"></property>  
  14.     <property name="maximumConnectionLifetime" value="${jdbc.maximumConnectionLifetime}"></property>  
  15.     <property name="prototypeCount" value="${jdbc.prototypeCount}"></property>  
  16.     <property name="houseKeepingSleepTime" value="${jdbc.houseKeepingSleepTime}"></property>  
  17.     <property name="simultaneousBuildThrottle" value="${jdbc.simultaneousBuildThrottle}"></property>  
  18.     <property name="houseKeepingTestSql" value="${jdbc.houseKeepingTestSql}"></property>  
  19.     <property name="verbose" value="${jdbc.verbose}"></property>  
  20.     <property name="statistics" value="${jdbc.statistics}"></property>  
  21.     <property name="statisticsLogLevel" value="${jdbc.statisticsLogLevel}"></property>  
  22. </bean>  
  23.   
  24.    <!--数据源 读-->  
  25.    <bean id="dataSourceR" class="org.logicalcobwebs.proxool.ProxoolDataSource">  
  26.        <property name="alias" value="ihotelR"></property>  
  27.        <property name="delegateProperties">  
  28.            <value>user=${jdbc.r.username},password=${jdbc.r.password}  
  29.            </value>  
  30.        </property>  
  31.        <property name="user" value="${jdbc.r.username}" />  
  32.        <property name="password" value="${jdbc.r.password}" />  
  33.        <property name="driver" value="${jdbc.r.driverClassName}" />  
  34.        <property name="driverUrl" value="${jdbc.r.url}" />  
  35.        <property name="maximumConnectionCount" value="${jdbc.maximumConnectionCount}"></property>  
  36.        <property name="maximumActiveTime" value="${jdbc.maximumActiveTime}"></property>  
  37.        <property name="maximumConnectionLifetime" value="${jdbc.maximumConnectionLifetime}"></property>  
  38.        <property name="prototypeCount" value="${jdbc.prototypeCount}"></property>  
  39.        <property name="houseKeepingSleepTime" value="${jdbc.houseKeepingSleepTime}"></property>  
  40.        <property name="simultaneousBuildThrottle" value="${jdbc.simultaneousBuildThrottle}"></property>  
  41.        <property name="houseKeepingTestSql" value="${jdbc.houseKeepingTestSql}"></property>  
  42.        <property name="verbose" value="${jdbc.verbose}"></property>  
  43.        <property name="statistics" value="${jdbc.statistics}"></property>  
  44.        <property name="statisticsLogLevel" value="${jdbc.statisticsLogLevel}"></property>  
  45.    </bean>  
  46.      
  47.    <!-- 动态数据源 -->  
  48.    <bean id="dynamicDataSource" class="com.dao.datasource.DynamicDataSource">  
  49.        <!-- 通过key-value关联数据源 -->  
  50.        <property name="targetDataSources">  
  51.            <map>  
  52.                <entry value-ref="dataSourceRW" key="dataSourceKeyRW"></entry>  
  53.                <entry value-ref="dataSourceR" key="dataSourceKeyR"></entry>  
  54.            </map>  
  55.        </property>  
  56.        <property name="defaultTargetDataSource" ref="dataSourceRW" />      
  57.    </bean>  
  58.   
  59. <!--mybatis与Spring整合 开始 -->  
  60. <bean id="sqlSessionFactory" name="sqlSessionFactory"  
  61.     class="org.mybatis.spring.SqlSessionFactoryBean">  
  62.     <property name="configLocation" value="classpath:conf/core/sqlMapConfig.xml" />  
  63.     <property name="dataSource" ref="dynamicDataSource" />  
  64. </bean>  

动态数据源dynamicDataSource中的dataSourceKeyRW、dataSourceKeyR就是

[java]
  1. protected abstract Object determineCurrentLookupKey();  
这个方法要返回的值。那么如何设置,让这个方法的返回值是根据我们的需要返回dataSourceKeyRW、dataSourceKeyR呢?由于这个方法没有入参,并且是spring自动调用的,因此考虑使用静态变量存储dataSource的key,在调用sql语句前设置静态变量的值,然后在这个方法中得到静态变量的值,返回。又考虑到多线程,同时可能会有很多请求,为避免线程之间相互干扰,考虑使用threadLocal。

先看存储dataSourceKey的容器类。

[java]
  1. public class DBContextHolder {  
  2.   
  3.     /** 
  4.      * 线程threadlocal 
  5.      */  
  6.     private static ThreadLocal<String> contextHolder = new ThreadLocal<>();  
  7.   
  8.     private String DB_TYPE_RW = "dataSourceKeyRW";  
  9.     private String DB_TYPE_R = "dataSourceKeyR";  
  10.   
  11.     public String getDbType() {  
  12.         String db = contextHolder.get();  
  13.         if (db == null) {  
  14.             db = DB_TYPE_RW;// 默认是读写库  
  15.         }  
  16.         return db;  
  17.     }  
  18.   
  19.     /** 
  20.      *  
  21.      * 设置本线程的dbtype 
  22.      *  
  23.      * @param str 
  24.      * @see [相关类/方法](可选) 
  25.      * @since [产品/模块版本](可选) 
  26.      */  
  27.     public void setDbType(String str) {  
  28.         contextHolder.set(str);  
  29.     }  
  30.   
  31.     /** 
  32.      * clearDBType 
  33.      *  
  34.      * @Title: clearDBType 
  35.      * @Description: 清理连接类型 
  36.      */  
  37.     public static void clearDBType() {  
  38.         contextHolder.remove();  
  39.     }  
  40. }  

动态数据源的实现类。

[java]
  1. public class DynamicDataSource extends AbstractRoutingDataSource {  
  2.   
  3.     /* 
  4.      * (non-Javadoc) 
  5.      * @see javax.sql.CommonDataSource#getParentLogger() 
  6.      */  
  7.     @Override  
  8.     public Logger getParentLogger() throws SQLFeatureNotSupportedException {  
  9.         // TODO Auto-generated method stub  
  10.         return null;  
  11.     }  
  12.   
  13.     /** 
  14.      *  
  15.      * override determineCurrentLookupKey 
  16.      * <p> 
  17.      * Title: determineCurrentLookupKey 
  18.      * </p> 
  19.      * <p> 
  20.      * Description: 自动查找datasource 
  21.      * </p> 
  22.      *  
  23.      * @return 
  24.      */  
  25.     @Override  
  26.     protected Object determineCurrentLookupKey() {  
  27.         return DBContextHolder.getDbType();  
  28.     }  
  29.   
  30. }  
在DAO层中设置数据库类型。
[java]
  1. /** 
  2.      * 添加邮件 
  3.      *  
  4.      * @param sms 
  5.      * @return 
  6.      */  
  7.     public boolean insertEmail(Email email) {  
  8.           
  9.         //根据具体需要设置不同的数据库  
  10.         DBContextHolder.setDbType(DBContextHolder.DB_TYPE_RW);  
  11.         //DBContextHolder.setDbType(DBContextHolder.DB_TYPE_R);  
  12.         int result = this.getSqlSession().insert(STATEMENT + ".addEntity",  
  13.                 email);  
  14.         return result == 1;  
  15.     }  

在本例中,我们是在DAO中指定数据库,我们也可以根据需要在service或者controller中指定DB类型,需要记住的是setDbType是针对线程维度的。要考虑多线程的问题。

你可能感兴趣的文章
VC++ UDP转TCP互发数据 UDP为服务端 TCP为客户端 可修改IP和端口最小化 2TCP/UDP中转
查看>>
仿养生网 帝国CMS 更新后域名栏目链接一直没变 解决方法:在后台地图--模板标签替换里直接全部替换
查看>>
微信扫码自动群发消息给所有人技术分析 之通过https请求获取微信网页版登录二维码图
查看>>
C#源码刷新网页 最小化托盘http get和post请求配置保存版权时间限制定时调用 单实例运行,如果已经运行则激活窗口到最前显示
查看>>
域名解密 商家联盟会员消费管理系统_连锁店会员积分系统 带微信(域名加密的) aqinxiaodian
查看>>
android蓝牙4.0BLE及2.0 2.1 apk 串口助手带16个自定义按键和自定义指令 字符接收 十六进制或字符发送
查看>>
爬虫采集 通用正则表达式
查看>>
织梦学习 变量的运用 添加新变量 删除新变量 添加上传视频mp4
查看>>
CocosCreator+VS2017提示“要求的 VS 版本:[2013, 2015, 2017]”解决办法 无法找到 v140_xp 的生成工具
查看>>
助学贷款系统导入预申请时问题解决办法汇总
查看>>
FTP连接阿里云不能获得列表目录等功能,能连接,21端口也打开了。原因FTP是双向的,阿里云入出方向安全组规则必须添加本地随机端口
查看>>
读书程序标准化建模--高效阅读学习,越学越有劲/趣
查看>>
不翻qiang搞定Android Studio Google库加载不下来的问题 打包生成apk android studio 3.2打灰机程序源码带详细注释
查看>>
仿照利用android系统源码资源文件,修改SeekBar颜色 前景与背景
查看>>
printf及String.format格式化测试
查看>>
android java 经典字符模式通信接收处理,标准modbus通讯协议接收处理提取数据
查看>>
10055自动进刀水钻机android蓝牙2.0SSP项目源码结构使用说明【版本更新、自动连接、控件批量处理、接收解析】
查看>>
Android Studio导入项目时常见问题的解决汇总,Eclipse项目转为Android Studio项目步骤报错万能解决方法汇总
查看>>
Widget.Material.Light.ProgressBar.Horizontal" (10302b8) is not a Drawable (color or path)错误解决
查看>>
解决java中文乱码,编码识别测试,汇总
查看>>