MySQL读写分离应用层实现
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                MySQL读写分离应用层实现
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.                        
                                基于Spring的AOP
在應(yīng)用層,實(shí)現(xiàn)讀寫分離 
 在請求進(jìn)入Service之前,使用AOP來做出判斷
判斷方式 
 是使用寫庫還是讀庫,判斷依據(jù)可以根據(jù)方法名判斷 
 比如,以query、find、get等開頭的就走讀庫,其他的走寫庫 
 
DynamicDataSource
定義動態(tài)數(shù)據(jù)源
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;/*** 定義動態(tài)數(shù)據(jù)源,實(shí)現(xiàn)通過集成Spring提供的AbstractRoutingDataSource,只需要實(shí)現(xiàn)determineCurrentLookupKey方法即可* * 由于DynamicDataSource是單例的,線程不安全的,所以采用ThreadLocal保證線程安全,由DynamicDataSourceHolder完成。**/ public class DynamicDataSource extends AbstractRoutingDataSource{@Overrideprotected Object determineCurrentLookupKey() {// 使用DynamicDataSourceHolder保證線程安全,并且得到當(dāng)前線程中的數(shù)據(jù)源keyreturn DynamicDataSourceHolder.getDataSourceKey();} }DynamicDataSourceHolder
使用ThreadLocal記錄數(shù)據(jù)源
/*** * 使用ThreadLocal技術(shù)來記錄當(dāng)前線程中的數(shù)據(jù)源的key**/ public class DynamicDataSourceHolder {//寫庫對應(yīng)的數(shù)據(jù)源keyprivate static final String MASTER = "master";//讀庫對應(yīng)的數(shù)據(jù)源keyprivate static final String SLAVE = "slave";//使用ThreadLocal記錄當(dāng)前線程的數(shù)據(jù)源keyprivate static final ThreadLocal<String> holder = new ThreadLocal<String>();/*** 設(shè)置數(shù)據(jù)源key* @param key*/public static void putDataSourceKey(String key) {holder.set(key);}/*** 獲取數(shù)據(jù)源key* @return*/public static String getDataSourceKey() {return holder.get();}/*** 標(biāo)記寫庫*/public static void markMaster(){putDataSourceKey(MASTER);}/*** 標(biāo)記讀庫*/public static void markSlave(){putDataSourceKey(SLAVE);} }DataSourceAspect
定義數(shù)據(jù)源的AOP切面
import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.JoinPoint;/*** 定義數(shù)據(jù)源的AOP切面,通過該Service的方法名判斷是應(yīng)該走讀庫還是寫庫**/ public class DataSourceAspect {/*** 在進(jìn)入Service方法之前執(zhí)行* * @param point 切面對象*/public void before(JoinPoint point) {// 獲取到當(dāng)前執(zhí)行的方法名String methodName = point.getSignature().getName();if (isSlave(methodName)) {// 標(biāo)記為讀庫DynamicDataSourceHolder.markSlave();} else {// 標(biāo)記為寫庫DynamicDataSourceHolder.markMaster();}}/*** 判斷是否為讀庫* * @param methodName* @return*/private Boolean isSlave(String methodName) {// 方法名以query、find、get開頭的方法名走從庫return StringUtils.startsWithAny(methodName, "query", "find", "get");} }數(shù)據(jù)源
配置2個(gè)數(shù)據(jù)源 
 jdbc.properties
定義連接池
applicationContext.xml
<!-- 配置連接池 --> <bean id="masterDataSource" class="com.jolbox.bonecp.BoneCPDataSource"destroy-method="close"><!-- 數(shù)據(jù)庫驅(qū)動 --><property name="driverClass" value="${jdbc.master.driver}" /><!-- 相應(yīng)驅(qū)動的jdbcUrl --><property name="jdbcUrl" value="${jdbc.master.url}" /><!-- 數(shù)據(jù)庫的用戶名 --><property name="username" value="${jdbc.master.username}" /><!-- 數(shù)據(jù)庫的密碼 --><property name="password" value="${jdbc.master.password}" /><!-- 檢查數(shù)據(jù)庫連接池中空閑連接的間隔時(shí)間,單位是分,默認(rèn)值:240,如果要取消則設(shè)置為0 --><property name="idleConnectionTestPeriod" value="60" /><!-- 連接池中未使用的鏈接最大存活時(shí)間,單位是分,默認(rèn)值:60,如果要永遠(yuǎn)存活設(shè)置為0 --><property name="idleMaxAge" value="30" /><!-- 每個(gè)分區(qū)最大的連接數(shù) --><property name="maxConnectionsPerPartition" value="150" /><!-- 每個(gè)分區(qū)最小的連接數(shù) --><property name="minConnectionsPerPartition" value="5" /> </bean><!-- 配置連接池 --> <bean id="slave01DataSource" class="com.jolbox.bonecp.BoneCPDataSource"destroy-method="close"><!-- 數(shù)據(jù)庫驅(qū)動 --><property name="driverClass" value="${jdbc.slave01.driver}" /><!-- 相應(yīng)驅(qū)動的jdbcUrl --><property name="jdbcUrl" value="${jdbc.slave01.url}" /><!-- 數(shù)據(jù)庫的用戶名 --><property name="username" value="${jdbc.slave01.username}" /><!-- 數(shù)據(jù)庫的密碼 --><property name="password" value="${jdbc.slave01.password}" /><!-- 檢查數(shù)據(jù)庫連接池中空閑連接的間隔時(shí)間,單位是分,默認(rèn)值:240,如果要取消則設(shè)置為0 --><property name="idleConnectionTestPeriod" value="60" /><!-- 連接池中未使用的鏈接最大存活時(shí)間,單位是分,默認(rèn)值:60,如果要永遠(yuǎn)存活設(shè)置為0 --><property name="idleMaxAge" value="30" /><!-- 每個(gè)分區(qū)最大的連接數(shù) --><property name="maxConnectionsPerPartition" value="150" /><!-- 每個(gè)分區(qū)最小的連接數(shù) --><property name="minConnectionsPerPartition" value="5" /> </bean>DataSource
定義數(shù)據(jù)源
<!-- 定義數(shù)據(jù)源,使用自己實(shí)現(xiàn)的數(shù)據(jù)源 --> <bean id="dataSource" class="cn.itcast.usermanage.spring.DynamicDataSource"><!-- 設(shè)置多個(gè)數(shù)據(jù)源 --><property name="targetDataSources"><map key-type="java.lang.String"><!-- 這個(gè)key需要和程序中的key一致 --><entry key="master" value-ref="masterDataSource" /><entry key="slave" value-ref="slave01DataSource" /></map></property><!-- 設(shè)置默認(rèn)的數(shù)據(jù)源,這里默認(rèn)走寫庫 --><property name="defaultTargetDataSource" ref="masterDataSource" /> </bean>事務(wù)管理
定義事務(wù)管理器
<!-- 定義事務(wù)管理器 --> <bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" /> </bean>事務(wù)策略
定義事務(wù)策略
<!-- 定義事務(wù)策略 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"><tx:attributes><!--定義查詢方法都是只讀的 --><tx:method name="query*" read-only="true" /><tx:method name="find*" read-only="true" /><tx:method name="get*" read-only="true" /><!-- 主庫執(zhí)行操作,事務(wù)傳播行為定義為默認(rèn)行為 --><tx:method name="save*" propagation="REQUIRED" /><tx:method name="update*" propagation="REQUIRED" /><tx:method name="delete*" propagation="REQUIRED" /><!--其他方法使用默認(rèn)事務(wù)策略 --><tx:method name="*" /></tx:attributes> </tx:advice>定義切面
自定義數(shù)據(jù)源在前面 
 先應(yīng)該確定數(shù)據(jù)源,然后,開啟事務(wù) 
 確保,該切面在最前面
總結(jié)
以上是生活随笔為你收集整理的MySQL读写分离应用层实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: MySQL读写分离中间件解决
- 下一篇: MySQL读写分离事务策略实现
