詳解使用spring aop實現(xiàn)業(yè)務層mysql 讀寫分離
spring aop , mysql 主從配置 實現(xiàn)讀寫分離,接下來把自己的配置過程,以及遇到的問題記錄下來,方便下次操作,也希望給一些朋友帶來幫助。
1.使用spring aop 攔截機制現(xiàn)數(shù)據(jù)源的動態(tài)選取。
import java.lang.annotation.ElementType; import java.lang.annotation.Target; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * RUNTIME * 編譯器將把注釋記錄在類文件中,在運行時 VM 將保留注釋,因此可以反射性地讀取。 * @author yangGuang * */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface DataSource { String value(); }
3.利用Spring的AbstractRoutingDataSource解決多數(shù)據(jù)源的問題
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; public class ChooseDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return HandleDataSource.getDataSource(); } }
4.利用ThreadLocal解決線程安全問題
public class HandleDataSource { public static final ThreadLocal<String> holder = new ThreadLocal<String>(); public static void putDataSource(String datasource) { holder.set(datasource); } public static String getDataSource() { return holder.get(); } }
5.定義一個數(shù)據(jù)源切面類,通過aop訪問,在spring配置文件中配置了,所以沒有使用aop注解。
import java.lang.reflect.Method; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; //@Aspect //@Component public class DataSourceAspect { //@Pointcut("execution(* com.apc.cms.service.*.*(..))") public void pointCut(){}; // @Before(value = "pointCut()") public void before(JoinPoint point) { Object target = point.getTarget(); System.out.println(target.toString()); String method = point.getSignature().getName(); System.out.println(method); Class<?>[] classz = target.getClass().getInterfaces(); Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()) .getMethod().getParameterTypes(); try { Method m = classz[0].getMethod(method, parameterTypes); System.out.println(m.getName()); if (m != null && m.isAnnotationPresent(DataSource.class)) { DataSource data = m.getAnnotation(DataSource.class); HandleDataSource.putDataSource(data.value()); } } catch (Exception e) { e.printStackTrace(); } } }
6.配置applicationContext.xml
<!-- 主庫數(shù)據(jù)源 --> <bean id="writeDataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close"> <property name="driverClass" value="com.mysql.jdbc.Driver"/> <property name="jdbcUrl" value="jdbc:mysql://172.22.14.6:3306/cpp?autoReconnect=true"/> <property name="username" value="root"/> <property name="password" value="root"/> <property name="partitionCount" value="4"/> <property name="releaseHelperThreads" value="3"/> <property name="acquireIncrement" value="2"/> <property name="maxConnectionsPerPartition" value="40"/> <property name="minConnectionsPerPartition" value="20"/> <property name="idleMaxAgeInSeconds" value="60"/> <property name="idleConnectionTestPeriodInSeconds" value="60"/> <property name="poolAvailabilityThreshold" value="5"/> </bean> <!-- 從庫數(shù)據(jù)源 --> <bean id="readDataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close"> <property name="driverClass" value="com.mysql.jdbc.Driver"/> <property name="jdbcUrl" value="jdbc:mysql://172.22.14.7:3306/cpp?autoReconnect=true"/> <property name="username" value="root"/> <property name="password" value="root"/> <property name="partitionCount" value="4"/> <property name="releaseHelperThreads" value="3"/> <property name="acquireIncrement" value="2"/> <property name="maxConnectionsPerPartition" value="40"/> <property name="minConnectionsPerPartition" value="20"/> <property name="idleMaxAgeInSeconds" value="60"/> <property name="idleConnectionTestPeriodInSeconds" value="60"/> <property name="poolAvailabilityThreshold" value="5"/> </bean> <!-- transaction manager, 事務管理 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 注解自動載入 --> <context:annotation-config /> <!--enale component scanning (beware that this does not enable mapper scanning!)--> <context:component-scan base-package="com.apc.cms.persistence.rdbms" /> <context:component-scan base-package="com.apc.cms.service"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Component" /> </context:component-scan> <context:component-scan base-package="com.apc.cms.auth" /> <!-- enable transaction demarcation with annotations --> <tx:annotation-driven /> <!-- define the SqlSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="typeAliasesPackage" value="com.apc.cms.model.domain" /> </bean> <!-- scan for mappers and let them be autowired --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.apc.cms.persistence" /> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> </bean> <bean id="dataSource" class="com.apc.cms.utils.ChooseDataSource"> <property name="targetDataSources"> <map key-type="java.lang.String"> <!-- write --> <entry key="write" value-ref="writeDataSource"/> <!-- read --> <entry key="read" value-ref="readDataSource"/> </map> </property> <property name="defaultTargetDataSource" ref="writeDataSource"/> </bean> <!-- 激活自動代理功能 --> <aop:aspectj-autoproxy proxy-target-class="true"/> <!-- 配置數(shù)據(jù)庫注解aop --> <bean id="dataSourceAspect" class="com.apc.cms.utils.DataSourceAspect" /> <aop:config> <aop:aspect id="c" ref="dataSourceAspect"> <aop:pointcut id="tx" expression="execution(* com.apc.cms.service..*.*(..))"/> <aop:before pointcut-ref="tx" method="before"/> </aop:aspect> </aop:config> <!-- 配置數(shù)據(jù)庫注解aop -->
7.使用注解,動態(tài)選擇數(shù)據(jù)源,分別走讀庫和寫庫。
@DataSource("write") public void update(User user) { userMapper.update(user); } @DataSource("read") public Document getDocById(long id) { return documentMapper.getById(id); }
測試寫操作:可以通過應用修改數(shù)據(jù),修改主庫數(shù)據(jù),發(fā)現(xiàn)從庫的數(shù)據(jù)被同步更新了,所以定義的write操作都是走的寫庫
測試讀操作: 后臺修改從庫數(shù)據(jù),查看主庫的數(shù)據(jù)沒有被修改,在應用頁面中刷新,發(fā)現(xiàn)讀的是從庫的數(shù)據(jù),說明讀寫分離ok。
遇到的問題總結(jié):
問題1:項目是maven工程,用到了Spring aop機制,除了spring的核心jar包以為,還需要用到的jar包有aspectj.jar,aspectjweaver.jar,aopalliance.jar查看項目中的pom,發(fā)現(xiàn)缺少依賴包,由于本地倉庫沒有這些jar,查找可以提供下載jar包的maven中央庫庫,配置到maven中,自動更新:
<repository> <id>nexus</id> <name>nexus</name> <url>http://repository.sonatype.org/content/groups/public/</url> <layout>default</layout> </repository>
配置項目依賴的jar,主要是缺少這兩個。
<dependency> <groupId>aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.5.4</version> </dependency> <dependency> <groupId>aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.5.4</version> lt;/dependency>
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
- Spring AOP切面解決數(shù)據(jù)庫讀寫分離實例詳解
- SpringMVC4+MyBatis+SQL Server2014實現(xiàn)數(shù)據(jù)庫讀寫分離
- SpringBoot集成Spring Data JPA及讀寫分離
- 詳解Spring AOP 實現(xiàn)主從讀寫分離
- Spring+MyBatis實現(xiàn)數(shù)據(jù)庫讀寫分離方案
- Spring配置動態(tài)數(shù)據(jù)源實現(xiàn)讀寫分離的方法
- Spring boot實現(xiàn)數(shù)據(jù)庫讀寫分離的方法
- Spring 實現(xiàn)數(shù)據(jù)庫讀寫分離的示例
- 使用Spring AOP實現(xiàn)MySQL數(shù)據(jù)庫讀寫分離案例分析(附demo)
- Spring動態(tài)數(shù)據(jù)源實現(xiàn)讀寫分離詳解
相關(guān)文章
SpringSecurity詳解整合JWT實現(xiàn)全過程
JWT作為一個開放的標準(?RFC?7519?),定義了一種簡潔的,自包含的方法用于通信雙方之間以Json對象的形式安全的傳遞信息。接下來通過本文給大家介紹springSecurity+jwt實現(xiàn)互踢功能,需要的朋友可以參考下2022-07-07Android讀取本地或網(wǎng)絡圖片并轉(zhuǎn)換為Bitmap
這篇文章主要為大家詳細介紹了Android讀取本地或網(wǎng)絡圖片,并轉(zhuǎn)換為Bitmap,感興趣的小伙伴們可以參考一下2016-08-08Kotlin中l(wèi)et、run、with、apply及also的用法和差別
作用域函數(shù)是Kotlin比較重要的一個特性,分為5種let、run、with、apply及also,這五個函數(shù)的工作方式非常相似,但是我們需要了解這5種函數(shù)的差異,以便在不同的場景更好的利用它,這篇文章主要介紹了Kotlin中l(wèi)et、run、with、apply及also的差別,需要的朋友可以參考下2023-11-11Spring+quartz實現(xiàn)定時發(fā)送郵件功能實例
spring提供的定時發(fā)送郵件功能一直深受廣大web開發(fā)者的喜愛,這篇文章主要介紹了Spring+quartz實現(xiàn)定時發(fā)送郵件功能實例,有興趣的可以了解一下。2017-03-03SpringBoot如何通過自定義注解實現(xiàn)權(quán)限檢查詳解
這篇文章主要給大家介紹了關(guān)于SpringBoot如何通過自定義注解實現(xiàn)權(quán)限檢查的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-10-10Java關(guān)鍵字synchronized原理與鎖的狀態(tài)詳解
在Java當中synchronized關(guān)鍵字通常是用來標記一個方法或者代碼塊。本文將通過示例為大家詳細介紹一下Synchronized的各種使用方法,需要的可以參考一下2022-08-08