日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

MySQL读写分离应用层实现

發(fā)布時(shí)間:2025/3/20 数据库 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MySQL读写分离应用层实现 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

基于Spring的AOP

在應(yīng)用層,實(shí)現(xiàn)讀寫(xiě)分離
在請(qǐng)求進(jìn)入Service之前,使用AOP來(lái)做出判斷

判斷方式
是使用寫(xiě)庫(kù)還是讀庫(kù),判斷依據(jù)可以根據(jù)方法名判斷
比如,以query、find、get等開(kāi)頭的就走讀庫(kù),其他的走寫(xiě)庫(kù)

DynamicDataSource

定義動(dòng)態(tài)數(shù)據(jù)源

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;/*** 定義動(dòng)態(tài)數(shù)據(jù)源,實(shí)現(xiàn)通過(guò)集成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ù)來(lái)記錄當(dāng)前線程中的數(shù)據(jù)源的key**/ public class DynamicDataSourceHolder {//寫(xiě)庫(kù)對(duì)應(yīng)的數(shù)據(jù)源keyprivate static final String MASTER = "master";//讀庫(kù)對(duì)應(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)記寫(xiě)庫(kù)*/public static void markMaster(){putDataSourceKey(MASTER);}/*** 標(biāo)記讀庫(kù)*/public static void markSlave(){putDataSourceKey(SLAVE);} }

DataSourceAspect

定義數(shù)據(jù)源的AOP切面

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

數(shù)據(jù)源

配置2個(gè)數(shù)據(jù)源
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"><!-- 數(shù)據(jù)庫(kù)驅(qū)動(dòng) --><property name="driverClass" value="${jdbc.master.driver}" /><!-- 相應(yīng)驅(qū)動(dòng)的jdbcUrl --><property name="jdbcUrl" value="${jdbc.master.url}" /><!-- 數(shù)據(jù)庫(kù)的用戶(hù)名 --><property name="username" value="${jdbc.master.username}" /><!-- 數(shù)據(jù)庫(kù)的密碼 --><property name="password" value="${jdbc.master.password}" /><!-- 檢查數(shù)據(jù)庫(kù)連接池中空閑連接的間隔時(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ù)庫(kù)驅(qū)動(dòng) --><property name="driverClass" value="${jdbc.slave01.driver}" /><!-- 相應(yīng)驅(qū)動(dòng)的jdbcUrl --><property name="jdbcUrl" value="${jdbc.slave01.url}" /><!-- 數(shù)據(jù)庫(kù)的用戶(hù)名 --><property name="username" value="${jdbc.slave01.username}" /><!-- 數(shù)據(jù)庫(kù)的密碼 --><property name="password" value="${jdbc.slave01.password}" /><!-- 檢查數(shù)據(jù)庫(kù)連接池中空閑連接的間隔時(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)走寫(xiě)庫(kù) --><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><!--定義查詢(xún)方法都是只讀的 --><tx:method name="query*" read-only="true" /><tx:method name="find*" read-only="true" /><tx:method name="get*" read-only="true" /><!-- 主庫(kù)執(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ù)源,然后,開(kāi)啟事務(wù)
確保,該切面在最前面

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

總結(jié)

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

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。