mysql+spring+mybatis实现数据库读写分离[代码配置] .
場景:一個讀數據源一個讀寫數據源。
?
原理:借助spring的【org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource】這個抽象類實現,看名字可以了解到是一個路由數據源的東西,這個類中有一個方法
/*** Determine the current lookup key. This will typically be* implemented to check a thread-bound transaction context.* <p>Allows for arbitrary keys. The returned key needs* to match the stored lookup key type, as resolved by the* {@link #resolveSpecifiedLookupKey} method.*/protected abstract Object determineCurrentLookupKey();
每次去連數據庫的時候,spring會調用這個方法去找對應的數據源。返回值即對應的數據源的LookUpKey.那么這個LookUpKey在哪定義的呢?看下面的dataBase.xml的配置
?
?
<!--數據源 讀寫 --><bean id="dataSourceRW" class="org.logicalcobwebs.proxool.ProxoolDataSource"><property name="alias" value="ihotelRW"></property><property name="delegateProperties"><value>user=${jdbc.username},password=${jdbc.password}</value></property><property name="user" value="${jdbc.username}" /><property name="password" value="${jdbc.password}" /><property name="driver" value="${jdbc.driverClassName}" /><property name="driverUrl" value="${jdbc.url}" /><property name="maximumConnectionCount" value="${jdbc.maximumConnectionCount}"></property><property name="maximumActiveTime" value="${jdbc.maximumActiveTime}"></property><property name="maximumConnectionLifetime" value="${jdbc.maximumConnectionLifetime}"></property><property name="prototypeCount" value="${jdbc.prototypeCount}"></property><property name="houseKeepingSleepTime" value="${jdbc.houseKeepingSleepTime}"></property><property name="simultaneousBuildThrottle" value="${jdbc.simultaneousBuildThrottle}"></property><property name="houseKeepingTestSql" value="${jdbc.houseKeepingTestSql}"></property><property name="verbose" value="${jdbc.verbose}"></property><property name="statistics" value="${jdbc.statistics}"></property><property name="statisticsLogLevel" value="${jdbc.statisticsLogLevel}"></property></bean><!--數據源 讀--><bean id="dataSourceR" class="org.logicalcobwebs.proxool.ProxoolDataSource"><property name="alias" value="ihotelR"></property><property name="delegateProperties"><value>user=${jdbc.r.username},password=${jdbc.r.password}</value></property><property name="user" value="${jdbc.r.username}" /><property name="password" value="${jdbc.r.password}" /><property name="driver" value="${jdbc.r.driverClassName}" /><property name="driverUrl" value="${jdbc.r.url}" /><property name="maximumConnectionCount" value="${jdbc.maximumConnectionCount}"></property><property name="maximumActiveTime" value="${jdbc.maximumActiveTime}"></property><property name="maximumConnectionLifetime" value="${jdbc.maximumConnectionLifetime}"></property><property name="prototypeCount" value="${jdbc.prototypeCount}"></property><property name="houseKeepingSleepTime" value="${jdbc.houseKeepingSleepTime}"></property><property name="simultaneousBuildThrottle" value="${jdbc.simultaneousBuildThrottle}"></property><property name="houseKeepingTestSql" value="${jdbc.houseKeepingTestSql}"></property><property name="verbose" value="${jdbc.verbose}"></property><property name="statistics" value="${jdbc.statistics}"></property><property name="statisticsLogLevel" value="${jdbc.statisticsLogLevel}"></property></bean><!-- 動態數據源 --><bean id="dynamicDataSource" class="com.dao.datasource.DynamicDataSource"><!-- 通過key-value關聯數據源 --><property name="targetDataSources"><map><entry value-ref="dataSourceRW" key="dataSourceKeyRW"></entry><entry value-ref="dataSourceR" key="dataSourceKeyR"></entry></map></property><property name="defaultTargetDataSource" ref="dataSourceRW" /> </bean><!--mybatis與Spring整合 開始 --><bean id="sqlSessionFactory" name="sqlSessionFactory"class="org.mybatis.spring.SqlSessionFactoryBean"><property name="configLocation" value="classpath:conf/core/sqlMapConfig.xml" /><property name="dataSource" ref="dynamicDataSource" /></bean>?
動態數據源dynamicDataSource中的dataSourceKeyRW、dataSourceKeyR就是
protected abstract Object determineCurrentLookupKey();這個方法要返回的值。那么如何設置,讓這個方法的返回值是根據我們的需要返回dataSourceKeyRW、dataSourceKeyR呢?由于這個方法沒有入參,并且是spring自動調用的,因此考慮使用靜態變量存儲dataSource的key,在調用sql語句前設置靜態變量的值,然后在這個方法中得到靜態變量的值,返回。又考慮到多線程,同時可能會有很多請求,為避免線程之間相互干擾,考慮使用threadLocal。
?
先看存儲dataSourceKey的容器類。
public class DBContextHolder {/*** 線程threadlocal*/private static ThreadLocal<String> contextHolder = new ThreadLocal<>();private String DB_TYPE_RW = "dataSourceKeyRW";private String DB_TYPE_R = "dataSourceKeyR";public String getDbType() {String db = contextHolder.get();if (db == null) {db = DB_TYPE_RW;// 默認是讀寫庫}return db;}/*** * 設置本線程的dbtype* * @param str* @see [相關類/方法](可選)* @since [產品/模塊版本](可選)*/public void setDbType(String str) {contextHolder.set(str);}/*** clearDBType* * @Title: clearDBType* @Description: 清理連接類型*/public static void clearDBType() {contextHolder.remove();} }?
?
動態數據源的實現類。
?
public class DynamicDataSource extends AbstractRoutingDataSource {/** (non-Javadoc)* @see javax.sql.CommonDataSource#getParentLogger()*/@Overridepublic Logger getParentLogger() throws SQLFeatureNotSupportedException {// TODO Auto-generated method stubreturn null;}/*** * override determineCurrentLookupKey* <p>* Title: determineCurrentLookupKey* </p>* <p>* Description: 自動查找datasource* </p>* * @return*/@Overrideprotected Object determineCurrentLookupKey() {return DBContextHolder.getDbType();}}
在DAO層中設置數據庫類型。
?
/*** 添加郵件* * @param sms* @return*/public boolean insertEmail(Email email) {//根據具體需要設置不同的數據庫DBContextHolder.setDbType(DBContextHolder.DB_TYPE_RW);//DBContextHolder.setDbType(DBContextHolder.DB_TYPE_R);int result = this.getSqlSession().insert(STATEMENT + ".addEntity",email);return result == 1;}?
?
?
在本例中,我們是在DAO中指定數據庫,我們也可以根據需要在service或者controller中指定DB類型,需要記住的是setDbType是針對線程維度的。要考慮多線程的問題。
總結
以上是生活随笔為你收集整理的mysql+spring+mybatis实现数据库读写分离[代码配置] .的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php5.5.25升级到php5.6.3
- 下一篇: Java后台 自动 翻页查询