欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring AOP如何實(shí)現(xiàn)注解式的Mybatis多數(shù)據(jù)源切換詳解

 更新時(shí)間:2020年11月10日 09:12:46   作者:mapleJia  
這篇文章主要給大家介紹了關(guān)于Spring AOP如何實(shí)現(xiàn)注解式的Mybatis多數(shù)據(jù)源切換的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

一、為什么要使用多數(shù)據(jù)源切換?

多數(shù)據(jù)源切換是為了滿(mǎn)足什么業(yè)務(wù)場(chǎng)景?正常情況下,一個(gè)微服務(wù)或者說(shuō)一個(gè)WEB項(xiàng)目,在使用Mybatis作為數(shù)據(jù)庫(kù)鏈接和操作框架的情況下通常只需要構(gòu)建一個(gè)系統(tǒng)庫(kù),在該系統(tǒng)庫(kù)創(chuàng)建業(yè)務(wù)表來(lái)滿(mǎn)足需求,當(dāng)然也有分為測(cè)試庫(kù)和正式庫(kù)dev/prod,不過(guò)這倆庫(kù)的切換是使用配置文件進(jìn)行切分的,在項(xiàng)目啟動(dòng)時(shí)或者打成maven JAR包指定environment-dev.properties或者environment-prod.properties。

那么當(dāng)程序運(yùn)行過(guò)程中,比如一個(gè)controller中既需要查詢(xún)數(shù)據(jù)庫(kù)A,又需要查詢(xún)數(shù)據(jù)庫(kù)B,而且兩者都希望用entity(Mybatis中用于與表結(jié)構(gòu)保持一直的bean)來(lái)接收查詢(xún)結(jié)果,即都希望走M(jìn)ybatis的entity-mapper-mapper.xml這么一套框架。這個(gè)時(shí)候最原始的方法是在代碼中手動(dòng)鏈接數(shù)據(jù)庫(kù)比如:

 var conn:Connection = null
 try {
 Class.forName("com.mysql.jdbc.Driver")
 conn = DriverManager.getConnection("url","username","password")
 val statement = conn.createStatement()
 val result = statement.executeQuery("select * from **** where **** ")
 while(result.next()){
 }
 }

  本文所采用的是修改dao層context配置文件添加基于Spring事務(wù)和AOP方式的注解式數(shù)據(jù)源切換。最終實(shí)現(xiàn)的效果如下:

 @Transactional //該注解表明該Service類(lèi)開(kāi)啟Spring事務(wù),事務(wù)的意思是指具有原子性的一個(gè)操作集合(本人理解),該事務(wù)做什么事在dao層的配置文件里配置,后面會(huì)講。


 @Service //表明為Service類(lèi),使用Component也行,Spring在啟動(dòng)時(shí)會(huì)掃描該類(lèi)將該類(lèi)所需要的bean全部構(gòu)建出來(lái)以供使用


 @TargetDataSource(name = "dataSource1") //重點(diǎn),自定義的AOP注解,指定該TestService1類(lèi)下的所有public方法都使用數(shù)據(jù)源dataSource1
 class TestService1{
 public void queryAllUser(){
  UserMapper userMapper = new UserMapper()
  userMapper.queryAllUser();
  System.out.println("使用數(shù)據(jù)源dataSource1查詢(xún)用戶(hù)信息")
 }
 }

 @Transactional 
 @Service 
 @TargetDataSource(name = "dataSource2") 
 class TestService2{

 public void queryAllBook(){
  BookMapper bookMapper = new BookMapper()
  bookMapper.queryAllBook();
  System.out.println("使用數(shù)據(jù)源dataSource2查詢(xún)書(shū)籍信息")
 }
 }

  在每一個(gè)需要切換數(shù)據(jù)源的Service層使用TargetDataSource(name= “***”)即可指定當(dāng)前線(xiàn)程的數(shù)據(jù)源,當(dāng)然別忘記@Transactional事務(wù)的添加,該事務(wù)用于Mybatis查詢(xún)數(shù)據(jù)時(shí)去獲取當(dāng)前線(xiàn)程的數(shù)據(jù)源為哪一個(gè)。如此在controller中正常調(diào)用Service中的方法就行了,如果需要查詢(xún)兩個(gè)數(shù)據(jù)庫(kù)那么分別調(diào)用兩個(gè)TestService中的方法即可。比如:

 //本人目前使用scala語(yǔ)言作為開(kāi)發(fā)語(yǔ)言,Java沒(méi)怎么寫(xiě)了,還是習(xí)慣Scala,以下程序還是使用Scala語(yǔ)言規(guī)范哈

 class testController{
 @AutoWired
 TestService1 testService1;
 @AutoWired
 TestService2 testService2;
 @RequestMapping(value = Array("/test"), produces = Array("application/json;charset=UTF-8"), method = Array(RequestMethod.GET))
  def test(): Unit = {
  val allUser = testService1.queryAllUser()
  println("使用TestService1查詢(xún)數(shù)據(jù)源1中的所有用戶(hù)")
  val allBook = testService2.queryAllBook("33287")
  println("使用TestService2查詢(xún)數(shù)據(jù)源2中的所有書(shū)籍信息")
  }
 }

二、如何實(shí)現(xiàn)

接下來(lái)就詳細(xì)講述如何在Spring MVC和Mybatis的單套數(shù)據(jù)源支持上擴(kuò)展多數(shù)據(jù)源切換能力。以下為雙數(shù)據(jù)源,三數(shù)據(jù)源的實(shí)現(xiàn)方式相同。

  1.首先在配置文件中添加第二個(gè)數(shù)據(jù)源的鏈接信息。

 environment-dev.properties
 #數(shù)據(jù)源1的鏈接信息
 db1.jdbc.username=xxx
 db1.jdbc.password=xxxxx
 db1.jdbc.driverClassName=com.mysql.jdbc.Driver
 db1.jdbc.url=xxxx?useUnicode=true&characterEncoding=utf8

 #新添加的數(shù)據(jù)源2的鏈接信息
 db2.jdbc.username=xxx
 db2.jdbc.password=xxxxx
 db2.jdbc.driverClassName=com.mysql.jdbc.Driver
 db2.jdbc.url=xxxx?useUnicode=true&characterEncoding=utf8

  2.在dao層的context.xml配置文件中添加基于注解的事務(wù)管理以及AOP切面配置

  (1)在配置文件中添加雙數(shù)據(jù)源,如下:

 <bean id="dataSource1" class="com.alibaba.druid.pool.DruidDataSource">
  <property name="driverClassName" value="${db1.jdbc.driverClassName}"/>
  <property name="password" value="${db1.jdbc.password}"/>
  <property name="username" value="${db1.jdbc.username}"/>
  <property name="url" value="${db1.jdbc.url}"/>
  <property name="initialSize" value="5"/>
  <property name="maxActive" value="10"/>
 </bean>

 <bean id="dataSource2" class="com.alibaba.druid.pool.DruidDataSource">
  <property name="driverClassName" value="${db2.jdbc.driverClassName}"/>
  <property name="password" value="${db2.jdbc.password}"/>
  <property name="username" value="${db2.jdbc.username}"/>
  <property name="url" value="${db2.jdbc.url}"/>
  <property name="initialSize" value="5"/>
  <property name="maxActive" value="10"/>
 </bean>

(2)使用AbstractRoutingDataSource實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)源選擇

  配置文件中添加

 <bean id="dataSource" class="common.dao.mysql.dataSourceManage.DynamicDataSource">
  <property name="targetDataSources">
  <map key-type="java.lang.String">
  <entry key="dataSource1" value-ref="dataSource1" />
  <entry key="dataSource2" value-ref="dataSource2" />
  </map>
  </property>
  <!-- 默認(rèn)使用dataSource1的數(shù)據(jù)源 --> 
  <property name="defaultTargetDataSource" ref="dataSource1" />
 </bean>

  在dao層創(chuàng)建dataSourceManage包,在包中創(chuàng)建如下類(lèi)DynamicDataSource,DataSourceHolder。

  類(lèi)一:

 import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
 public class DynamicDataSource extends AbstractRoutingDataSource {
 @Override
 protected Object determineCurrentLookupKey() {
  return DataSourceHolder.getDataSoure();
 }
 }

  類(lèi)二:

 public class DataSourceHolder {

 //線(xiàn)程本地環(huán)境
 private static final ThreadLocal<String> dataSources = new ThreadLocal<String>();

 //設(shè)置數(shù)據(jù)源
 public static void setDataSource(String customerType) {
  dataSources.set(customerType);
 }

 //獲取數(shù)據(jù)源
 public static String getDataSoure() {
  return (String) dataSources.get();
 }

 //清除數(shù)據(jù)源
 public static void clearDataSource() {
  dataSources.remove();
 }
 }

  Spring boot提供了AbstractRoutingDataSource 根據(jù)用戶(hù)定義的規(guī)則選擇當(dāng)前的數(shù)據(jù)源,這樣我們可以在執(zhí)行查詢(xún)之前,設(shè)置使用的數(shù)據(jù)源。實(shí)現(xiàn)可動(dòng)態(tài)路由的數(shù)據(jù)源,在每次數(shù)據(jù)庫(kù)查詢(xún)操作前執(zhí)行。它的抽象方法 determineCurrentLookupKey() 決定使用哪個(gè)數(shù)據(jù)源。以上完成數(shù)據(jù)庫(kù)操作之前的數(shù)據(jù)源選擇,使用的是DataSourceHolder.getDataSoure();

(3)添加Spring事務(wù),確定在業(yè)務(wù)代碼中查詢(xún)數(shù)據(jù)庫(kù)時(shí),由Spring事務(wù)去執(zhí)行以上對(duì)數(shù)據(jù)源的選擇,這樣既不影響業(yè)務(wù)代碼又能提供事務(wù)的性質(zhì)保證。

在配置文件中添加

 <!-- 定義事務(wù)管理器(聲明式的事務(wù)) -->
 <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
 <property name="dataSource" ref="dataSource" />
 </bean>
 <!-- 將所有具有@Transactional注解的Bean自動(dòng)配置為聲明式事務(wù)支持 --> 
 <tx:annotation-driven transaction-manager="dataSourceTransactionManager" />

 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
 <property name="dataSource" ref="dataSource"/>
 <property name="mapperLocations">
 <list>
  <value>classpath:common/dao/mysql/mapper/*Mapper.xml</value>
 </list>
 </property>
 </bean>

  注意配置sqlSessionFactory中使用的數(shù)據(jù)源需要和事務(wù)配置中的保持一直。以及配置文件的頂層bean需要添加 xmlns:tx="http://www.springframework.org/schema/tx"和xsi:schemaLocation中添加http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd

  (4)配置AOP提供Service層注解式聲明使用的數(shù)據(jù)源

  首先在配置文件中添加AOP支持xmlns:aop="http://www.springframework.org/schema/aop",xsi:schemaLocation中添加http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd

 <!--配置切面的bean DataSourceExchange 自定義的切面類(lèi)實(shí)現(xiàn)數(shù)據(jù)源切換-->
 <bean id="dataSourceExchange" class="common.dao.mysql.datasource.DataSourceExchange" />
 <!--配置AOP -->
 <aop:config>
  <!--配置切點(diǎn)表達(dá)式 定義dataSourceExchange中的攔截使用范圍-->
  <aop:pointcut id="servicePointcut" expression="execution(* common.dao.mysql.service.*.*(..))"/>
  <aop:advisor advice-ref="dataSourceExchange" pointcut-ref="servicePointcut" order="1" />
 </aop:config>

  其中execution(* common.dao.mysql.service.*.*(..))為service下的所有類(lèi)(指TestService1和TestService2)的所有public方法都加上切面代理即使用dataSourceExchange處理。

  然后在dataSourceManage包下創(chuàng)建DataSourceExchange類(lèi)實(shí)現(xiàn)AfterReturningAdvice,MethodBeforeAdvice兩個(gè)aop通知

 import java.lang.reflect.Method;
 import org.springframework.aop.AfterReturningAdvice;
 import org.springframework.aop.MethodBeforeAdvice;

 public class DataSourceExchange implements MethodBeforeAdvice, AfterReturningAdvice {

 @Override
 public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
  DataSourceHolder.clearDataSource();
 }

 @Override
 public void before(Method method, Object[] objects, Object o) throws Throwable {

  //這里TargetDataSource是自定義注解,method為查詢(xún)數(shù)據(jù)庫(kù)的方法比如一中的queryAllUser(),Objects為傳給該方法的參數(shù)數(shù)組,o為調(diào)用該方法的對(duì)象,比如val allUser =      
  //testService1.queryAllUser()中的testService1
  if (method.isAnnotationPresent(TargetDataSource.class)) {
  TargetDataSource dataSource = method.getAnnotation(TargetDataSource.class);
  DataSourceHolder.setDataSource(dataSource.name());
  } else {
  if (o.getClass().isAnnotationPresent(TargetDataSource.class)) {
   TargetDataSource dataSource = o.getClass().getAnnotation(TargetDataSource.class);
   DataSourceHolder.setDataSource(dataSource.name());
  }
  }
 }
 }

  然后在dataSourceManage包下創(chuàng)建TargetDataSource注解類(lèi)

 import java.lang.annotation.*;

 @Target({ElementType.METHOD, ElementType.TYPE})
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
 public @interface TargetDataSource {
 String name() default "dataSource1";
 }

  以上配置完成之后即可達(dá)成一中的最終效果。

  完整的dao配置文件內(nèi)容如下

 <beans
  xmlns="http://www.springframework.org/schema/beans"
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:tx="http://www.springframework.org/schema/tx"
  xmlns:aop="http://www.springframework.org/schema/aop"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop    
    https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd ">

 <context:annotation-config/>
 <context:component-scan base-package="com.test.common.dao"/>
 <bean id="dataSource1" class="com.alibaba.druid.pool.DruidDataSource">
   <property name="driverClassName" value="${db1.jdbc.driverClassName}"/>
   <property name="password" value="${db1.jdbc.password}"/>
   <property name="username" value="${db1.jdbc.username}"/>
   <property name="url" value="${db1.jdbc.url}"/>
   <property name="initialSize" value="5"/>
   <property name="maxActive" value="10"/>
 </bean>

 <bean id="dataSource2" class="com.alibaba.druid.pool.DruidDataSource">
  <property name="driverClassName" value="${db2.jdbc.driverClassName}"/>
  <property name="password" value="${db2.jdbc.password}"/>
  <property name="username" value="${db2.jdbc.username}"/>
  <property name="url" value="${db2.jdbc.url}"/>
  <property name="initialSize" value="5"/>
  <property name="maxActive" value="10"/>
 </bean>

 <bean id="dataSource" class="test.common.dao.mysql.dataSourceManage.DynamicDataSource">
  <property name="targetDataSources">
   <map key-type="java.lang.String">
   <entry key="dataSource1" value-ref="dataSource1" />
   <entry key="dataSource2" value-ref="dataSource2" />
   </map>
  </property>
   <!-- 默認(rèn)使用dataSource1的數(shù)據(jù)源 --> 
  <property name="defaultTargetDataSource" ref="dataSource1" />
 </bean>

 <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource" />
 </bean>
 <tx:annotation-driven transaction-manager="dataSourceTransactionManager" />
 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
 <property name="dataSource" ref="dataSource"/>
 <property name="mapperLocations">
  <list>
  <value>classpath:test/common/dao/mysql/mapper/*Mapper.xml</value>
  </list>
 </property>
 </bean>

 <!--配置可以批量執(zhí)行的sqlSession -->
 <!--配置切面的bean -->
 <bean id="dataSourceExchange" class="test.common.dao.mysql.datasource.DataSourceExchange" />
 <!--配置AOP -->
 <aop:config>
 <!--配置切點(diǎn)表達(dá)式 -->
  <aop:pointcut id="servicePointcut" expression="execution(* test.common.dao.mysql.service.*.*(..))"/>
  <aop:advisor advice-ref="dataSourceExchange" pointcut-ref="servicePointcut" order="1" />
 </aop:config>

 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
 <property name="basePackage" value="test.common.dao"/>
 <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
 </bean>
 </beans>

到此這篇關(guān)于Spring AOP如何實(shí)現(xiàn)注解式的Mybatis多數(shù)據(jù)源切換的文章就介紹到這了,更多相關(guān)Spring AOP注解式的Mybatis多數(shù)據(jù)源切換內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • IDEA中設(shè)置Run Dashboard方式

    IDEA中設(shè)置Run Dashboard方式

    這篇文章主要介紹了IDEA中設(shè)置Run Dashboard方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • JAVA實(shí)現(xiàn)打印ascii碼表代碼

    JAVA實(shí)現(xiàn)打印ascii碼表代碼

    這篇文章主要介紹了JAVA實(shí)現(xiàn)打印ascii碼表代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-08-08
  • Spring中Bean的生命周期及實(shí)例化操作詳解

    Spring中Bean的生命周期及實(shí)例化操作詳解

    這篇文章主要介紹了Spring中Bean的生命周期及實(shí)例化操作詳解,spring的核心思想之一IOC就是通過(guò)IOC容器對(duì)Bean的創(chuàng)建和各個(gè)bean之間的依賴(lài)關(guān)系進(jìn)行操作,今天就來(lái)和大家分享一下bean的生命周期相關(guān)知識(shí)點(diǎn),需要的朋友可以參考下
    2023-08-08
  • java反射機(jī)制根據(jù)屬性名獲取屬性值的操作

    java反射機(jī)制根據(jù)屬性名獲取屬性值的操作

    這篇文章主要介紹了java反射機(jī)制根據(jù)屬性名獲取屬性值的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-10-10
  • 使用spring的restTemplate注意點(diǎn)

    使用spring的restTemplate注意點(diǎn)

    這篇文章主要介紹了使用spring的restTemplate注意點(diǎn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • 詳解Kotlin中如何實(shí)現(xiàn)類(lèi)似Java或C#中的靜態(tài)方法

    詳解Kotlin中如何實(shí)現(xiàn)類(lèi)似Java或C#中的靜態(tài)方法

    Kotlin中如何實(shí)現(xiàn)類(lèi)似Java或C#中的靜態(tài)方法,本文總結(jié)了幾種方法,分別是:包級(jí)函數(shù)、伴生對(duì)象、擴(kuò)展函數(shù)和對(duì)象聲明。這需要大家根據(jù)不同的情況進(jìn)行選擇。
    2017-05-05
  • 詳解springmvc如何處理接受http請(qǐng)求

    詳解springmvc如何處理接受http請(qǐng)求

    這篇文章主要給大家介紹了springmvc如何處理接受http請(qǐng)求,文中通過(guò)代碼示例給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-02-02
  • 基于Java實(shí)現(xiàn)文件和base64字符串轉(zhuǎn)換

    基于Java實(shí)現(xiàn)文件和base64字符串轉(zhuǎn)換

    這篇文章主要介紹了基于Java實(shí)現(xiàn)文件和base64字符串轉(zhuǎn)換,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01
  • java網(wǎng)上圖書(shū)商城(4)購(gòu)物車(chē)模塊1

    java網(wǎng)上圖書(shū)商城(4)購(gòu)物車(chē)模塊1

    這篇文章主要為大家詳細(xì)介紹了java網(wǎng)上圖書(shū)商城,購(gòu)物車(chē)模塊,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • Java基數(shù)排序radix sort原理及用法解析

    Java基數(shù)排序radix sort原理及用法解析

    這篇文章主要介紹了Java基數(shù)排序radix sort原理及用法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06

最新評(píng)論