日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

MySQL读写分离应用层实现

發布時間:2025/3/20 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MySQL读写分离应用层实现 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

基于Spring的AOP

在應用層,實現讀寫分離
在請求進入Service之前,使用AOP來做出判斷

判斷方式
是使用寫庫還是讀庫,判斷依據可以根據方法名判斷
比如,以query、find、get等開頭的就走讀庫,其他的走寫庫

DynamicDataSource

定義動態數據源

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;/*** 定義動態數據源,實現通過集成Spring提供的AbstractRoutingDataSource,只需要實現determineCurrentLookupKey方法即可* * 由于DynamicDataSource是單例的,線程不安全的,所以采用ThreadLocal保證線程安全,由DynamicDataSourceHolder完成。**/ public class DynamicDataSource extends AbstractRoutingDataSource{@Overrideprotected Object determineCurrentLookupKey() {// 使用DynamicDataSourceHolder保證線程安全,并且得到當前線程中的數據源keyreturn DynamicDataSourceHolder.getDataSourceKey();} }

DynamicDataSourceHolder

使用ThreadLocal記錄數據源

/*** * 使用ThreadLocal技術來記錄當前線程中的數據源的key**/ public class DynamicDataSourceHolder {//寫庫對應的數據源keyprivate static final String MASTER = "master";//讀庫對應的數據源keyprivate static final String SLAVE = "slave";//使用ThreadLocal記錄當前線程的數據源keyprivate static final ThreadLocal<String> holder = new ThreadLocal<String>();/*** 設置數據源key* @param key*/public static void putDataSourceKey(String key) {holder.set(key);}/*** 獲取數據源key* @return*/public static String getDataSourceKey() {return holder.get();}/*** 標記寫庫*/public static void markMaster(){putDataSourceKey(MASTER);}/*** 標記讀庫*/public static void markSlave(){putDataSourceKey(SLAVE);} }

DataSourceAspect

定義數據源的AOP切面

import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.JoinPoint;/*** 定義數據源的AOP切面,通過該Service的方法名判斷是應該走讀庫還是寫庫**/ public class DataSourceAspect {/*** 在進入Service方法之前執行* * @param point 切面對象*/public void before(JoinPoint point) {// 獲取到當前執行的方法名String methodName = point.getSignature().getName();if (isSlave(methodName)) {// 標記為讀庫DynamicDataSourceHolder.markSlave();} else {// 標記為寫庫DynamicDataSourceHolder.markMaster();}}/*** 判斷是否為讀庫* * @param methodName* @return*/private Boolean isSlave(String methodName) {// 方法名以query、find、get開頭的方法名走從庫return StringUtils.startsWithAny(methodName, "query", "find", "get");} }

數據源

配置2個數據源
jdbc.properties

jdbc.master.driver=com.mysql.jdbc.Driver jdbc.master.url=jdbc:mysql://127.0.0.1:3306/mybatis_1128?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true jdbc.master.username=root jdbc.master.password=123456jdbc.slave01.driver=com.mysql.jdbc.Driver jdbc.slave01.url=jdbc:mysql://127.0.0.1:3307/mybatis_1128?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true jdbc.slave01.username=root jdbc.slave01.password=123456

定義連接池

applicationContext.xml

<!-- 配置連接池 --> <bean id="masterDataSource" class="com.jolbox.bonecp.BoneCPDataSource"destroy-method="close"><!-- 數據庫驅動 --><property name="driverClass" value="${jdbc.master.driver}" /><!-- 相應驅動的jdbcUrl --><property name="jdbcUrl" value="${jdbc.master.url}" /><!-- 數據庫的用戶名 --><property name="username" value="${jdbc.master.username}" /><!-- 數據庫的密碼 --><property name="password" value="${jdbc.master.password}" /><!-- 檢查數據庫連接池中空閑連接的間隔時間,單位是分,默認值:240,如果要取消則設置為0 --><property name="idleConnectionTestPeriod" value="60" /><!-- 連接池中未使用的鏈接最大存活時間,單位是分,默認值:60,如果要永遠存活設置為0 --><property name="idleMaxAge" value="30" /><!-- 每個分區最大的連接數 --><property name="maxConnectionsPerPartition" value="150" /><!-- 每個分區最小的連接數 --><property name="minConnectionsPerPartition" value="5" /> </bean><!-- 配置連接池 --> <bean id="slave01DataSource" class="com.jolbox.bonecp.BoneCPDataSource"destroy-method="close"><!-- 數據庫驅動 --><property name="driverClass" value="${jdbc.slave01.driver}" /><!-- 相應驅動的jdbcUrl --><property name="jdbcUrl" value="${jdbc.slave01.url}" /><!-- 數據庫的用戶名 --><property name="username" value="${jdbc.slave01.username}" /><!-- 數據庫的密碼 --><property name="password" value="${jdbc.slave01.password}" /><!-- 檢查數據庫連接池中空閑連接的間隔時間,單位是分,默認值:240,如果要取消則設置為0 --><property name="idleConnectionTestPeriod" value="60" /><!-- 連接池中未使用的鏈接最大存活時間,單位是分,默認值:60,如果要永遠存活設置為0 --><property name="idleMaxAge" value="30" /><!-- 每個分區最大的連接數 --><property name="maxConnectionsPerPartition" value="150" /><!-- 每個分區最小的連接數 --><property name="minConnectionsPerPartition" value="5" /> </bean>

DataSource

定義數據源

<!-- 定義數據源,使用自己實現的數據源 --> <bean id="dataSource" class="cn.itcast.usermanage.spring.DynamicDataSource"><!-- 設置多個數據源 --><property name="targetDataSources"><map key-type="java.lang.String"><!-- 這個key需要和程序中的key一致 --><entry key="master" value-ref="masterDataSource" /><entry key="slave" value-ref="slave01DataSource" /></map></property><!-- 設置默認的數據源,這里默認走寫庫 --><property name="defaultTargetDataSource" ref="masterDataSource" /> </bean>

事務管理

定義事務管理器

<!-- 定義事務管理器 --> <bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource" /> </bean>

事務策略

定義事務策略

<!-- 定義事務策略 --> <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" /><!-- 主庫執行操作,事務傳播行為定義為默認行為 --><tx:method name="save*" propagation="REQUIRED" /><tx:method name="update*" propagation="REQUIRED" /><tx:method name="delete*" propagation="REQUIRED" /><!--其他方法使用默認事務策略 --><tx:method name="*" /></tx:attributes> </tx:advice>

定義切面

自定義數據源在前面
先應該確定數據源,然后,開啟事務
確保,該切面在最前面

<!-- 定義AOP切面處理器 --> <bean class="cn.itcast.usermanage.spring.DataSourceAspect" id="dataSourceAspect" /> <aop:config><!-- 定義切面,所有的service的所有方法 --><aop:pointcut id="txPointcut"expression="execution(* xx.xxx.xxxxxxx.service.*.*(..))" /><!-- 應用事務策略到Service切面 --><aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" /><!-- 將切面應用到自定義的切面處理器上,-9999保證該切面優先級最高執行 --><aop:aspect ref="dataSourceAspect" order="-9999"><aop:before method="before" pointcut-ref="txPointcut" /></aop:aspect> </aop:config>

總結

以上是生活随笔為你收集整理的MySQL读写分离应用层实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。