日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

Spring AOP如何實現注解式的Mybatis多數據源切換詳解

瀏覽:101日期:2023-08-03 08:46:11

一、為什么要使用多數據源切換?

多數據源切換是為了滿足什么業務場景?正常情況下,一個微服務或者說一個WEB項目,在使用Mybatis作為數據庫鏈接和操作框架的情況下通常只需要構建一個系統庫,在該系統庫創建業務表來滿足需求,當然也有分為測試庫和正式庫dev/prod,不過這倆庫的切換是使用配置文件進行切分的,在項目啟動時或者打成maven JAR包指定environment-dev.properties或者environment-prod.properties。

那么當程序運行過程中,比如一個controller中既需要查詢數據庫A,又需要查詢數據庫B,而且兩者都希望用entity(Mybatis中用于與表結構保持一直的bean)來接收查詢結果,即都希望走Mybatis的entity-mapper-mapper.xml這么一套框架。這個時候最原始的方法是在代碼中手動鏈接數據庫比如:

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事務和AOP方式的注解式數據源切換。最終實現的效果如下:

@Transactional //該注解表明該Service類開啟Spring事務,事務的意思是指具有原子性的一個操作集合(本人理解),該事務做什么事在dao層的配置文件里配置,后面會講。 @Service //表明為Service類,使用Component也行,Spring在啟動時會掃描該類將該類所需要的bean全部構建出來以供使用 @TargetDataSource(name = 'dataSource1') //重點,自定義的AOP注解,指定該TestService1類下的所有public方法都使用數據源dataSource1 class TestService1{ public void queryAllUser(){ UserMapper userMapper = new UserMapper() userMapper.queryAllUser(); System.out.println('使用數據源dataSource1查詢用戶信息') } } @Transactional @Service @TargetDataSource(name = 'dataSource2') class TestService2{ public void queryAllBook(){ BookMapper bookMapper = new BookMapper() bookMapper.queryAllBook(); System.out.println('使用數據源dataSource2查詢書籍信息') } }

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

//本人目前使用scala語言作為開發語言,Java沒怎么寫了,還是習慣Scala,以下程序還是使用Scala語言規范哈 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查詢數據源1中的所有用戶') val allBook = testService2.queryAllBook('33287') println('使用TestService2查詢數據源2中的所有書籍信息') } }

二、如何實現

接下來就詳細講述如何在Spring MVC和Mybatis的單套數據源支持上擴展多數據源切換能力。以下為雙數據源,三數據源的實現方式相同。

1.首先在配置文件中添加第二個數據源的鏈接信息。

environment-dev.properties #數據源1的鏈接信息 db1.jdbc.username=xxx db1.jdbc.password=xxxxx db1.jdbc.driverClassName=com.mysql.jdbc.Driver db1.jdbc.url=xxxx?useUnicode=true&characterEncoding=utf8 #新添加的數據源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配置文件中添加基于注解的事務管理以及AOP切面配置

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

<bean 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 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實現動態數據源選擇

配置文件中添加

<bean 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> <!-- 默認使用dataSource1的數據源 --> <property name='defaultTargetDataSource' ref='dataSource1' /> </bean>

在dao層創建dataSourceManage包,在包中創建如下類DynamicDataSource,DataSourceHolder。

類一:

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

類二:

public class DataSourceHolder { //線程本地環境 private static final ThreadLocal<String> dataSources = new ThreadLocal<String>(); //設置數據源 public static void setDataSource(String customerType) { dataSources.set(customerType); } //獲取數據源 public static String getDataSoure() { return (String) dataSources.get(); } //清除數據源 public static void clearDataSource() { dataSources.remove(); } }

Spring boot提供了AbstractRoutingDataSource 根據用戶定義的規則選擇當前的數據源,這樣我們可以在執行查詢之前,設置使用的數據源。實現可動態路由的數據源,在每次數據庫查詢操作前執行。它的抽象方法 determineCurrentLookupKey() 決定使用哪個數據源。以上完成數據庫操作之前的數據源選擇,使用的是DataSourceHolder.getDataSoure();

(3)添加Spring事務,確定在業務代碼中查詢數據庫時,由Spring事務去執行以上對數據源的選擇,這樣既不影響業務代碼又能提供事務的性質保證。

在配置文件中添加

<!-- 定義事務管理器(聲明式的事務) --> <bean class='org.springframework.jdbc.datasource.DataSourceTransactionManager'> <property name='dataSource' ref='dataSource' /> </bean> <!-- 將所有具有@Transactional注解的Bean自動配置為聲明式事務支持 --> <tx:annotation-driven transaction-manager='dataSourceTransactionManager' /> <bean 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中使用的數據源需要和事務配置中的保持一直。以及配置文件的頂層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層注解式聲明使用的數據源

首先在配置文件中添加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 自定義的切面類實現數據源切換--> <bean /> <!--配置AOP --> <aop:config> <!--配置切點表達式 定義dataSourceExchange中的攔截使用范圍--> <aop:pointcut expression='execution(* common.dao.mysql.service.*.*(..))'/> <aop:advisor advice-ref='dataSourceExchange' pointcut-ref='servicePointcut' order='1' /> </aop:config>

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

然后在dataSourceManage包下創建DataSourceExchange類實現AfterReturningAdvice,MethodBeforeAdvice兩個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為查詢數據庫的方法比如一中的queryAllUser(),Objects為傳給該方法的參數數組,o為調用該方法的對象,比如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包下創建TargetDataSource注解類

import java.lang.annotation.*; @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface TargetDataSource { String name() default 'dataSource1'; }

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

完整的dao配置文件內容如下

<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/aophttps://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 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 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 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> <!-- 默認使用dataSource1的數據源 --> <property name='defaultTargetDataSource' ref='dataSource1' /> </bean> <bean class='org.springframework.jdbc.datasource.DataSourceTransactionManager'> <property name='dataSource' ref='dataSource' /> </bean> <tx:annotation-driven transaction-manager='dataSourceTransactionManager' /> <bean 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> <!--配置可以批量執行的sqlSession --> <!--配置切面的bean --> <bean /> <!--配置AOP --> <aop:config> <!--配置切點表達式 --> <aop:pointcut 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>

到此這篇關于Spring AOP如何實現注解式的Mybatis多數據源切換的文章就介紹到這了,更多相關Spring AOP注解式的Mybatis多數據源切換內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Spring
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
秋霞国产精品| 国产精品对白| 久久精品免视看国产成人| aa国产精品| 国产综合精品| 99pao成人国产永久免费视频| 国产一级久久| 视频一区中文字幕精品| 91成人在线| 国产精品视频一区二区三区综合| 麻豆视频一区| 一区在线免费观看| 日韩国产欧美一区二区三区| 国产三级精品三级在线观看国产| 青青青国产精品| 国产精品1区| 91欧美在线| 9国产精品视频| 综合一区二区三区| 欧美激情网址| 超级白嫩亚洲国产第一| 久久久久99| 久久国产99| 日韩av中文字幕一区二区三区| 免费在线欧美黄色| 欧美精品高清| 日韩影院免费视频| 国产亚洲久久| 国产 日韩 欧美一区| 丝袜诱惑制服诱惑色一区在线观看| 日韩av一区二| jizzjizz中国精品麻豆| 国产女优一区| 久久不卡日韩美女| 日本精品影院| 亚洲制服欧美另类| 九九久久国产| 亚洲欧美日本国产专区一区| 国产精品久一| 狠狠色综合网| 国产精品tv| 午夜精品亚洲| 国产精品白丝一区二区三区| japanese国产精品| 亚洲精品亚洲人成在线观看| 国产精品99一区二区三| 亚洲免费影视| 色乱码一区二区三区网站| 国产精品黄色| 亚洲激精日韩激精欧美精品| 国产精品久av福利在线观看| 韩日一区二区三区| 国产欧美一区二区三区国产幕精品| 日韩精品麻豆| 国产精品亚洲一区二区在线观看| 蜜桃视频欧美| 卡一卡二国产精品| 免播放器亚洲一区| 亚洲综合在线电影| 国产乱子精品一区二区在线观看| 一区福利视频| 日本不良网站在线观看| 婷婷视频一区二区三区| 国产成人精品亚洲日本在线观看| 日韩av黄色在线| 欧美日韩国产一区二区三区不卡 | 亚洲伊人精品酒店| 日韩av一级| 欧美激情福利| 首页亚洲欧美制服丝腿| 日韩精品诱惑一区?区三区| 婷婷五月色综合香五月| 久久视频国产| 成人精品视频| 精品国产乱码久久久| 麻豆视频一区二区| 视频精品一区二区| 欧美日韩午夜| 亚洲精品国产偷自在线观看| 久久亚洲图片| 亚洲欧洲美洲国产香蕉| 久久精品日韩欧美| 亚洲精品美女| 9色国产精品| 在线一区视频观看| 精品国产一级| 六月丁香综合在线视频| 日韩高清在线不卡| 婷婷综合网站| 久久人人99| 日韩中文欧美| 福利视频一区| 精品久久99| 久久丁香四色| 国产精品亚洲欧美日韩一区在线| 亚洲91网站| 免费人成精品欧美精品 | 99久精品视频在线观看视频| 精品一区二区三区在线观看视频| 国产精品视频一区二区三区综合| 欧美日韩亚洲三区| 亚洲乱码久久| 麻豆精品网站| 亚洲一区日韩在线| 欧美精品导航| 欧美日韩xxxx| 日韩高清不卡在线| 蜜臀久久99精品久久久久久9| 亚洲国产一区二区在线观看 | 欧美13videosex性极品| 91亚洲国产| av最新在线| 久久精品免费看| 捆绑调教美女网站视频一区| 久久久久伊人| 国产精品国产三级在线观看| 久久精品女人| 夜鲁夜鲁夜鲁视频在线播放| 日韩中文首页| 怡红院精品视频在线观看极品| 国精品一区二区| 六月婷婷一区| 91精品丝袜国产高跟在线| 欧美亚洲免费| 麻豆91在线播放| se01亚洲视频 | 午夜久久免费观看| 狠狠操综合网| 视频一区日韩精品| 国产欧美日韩在线观看视频| 久久精品亚洲一区二区| 精品丝袜久久| 国产91久久精品一区二区| 亚洲男女自偷自拍| 亚洲欧美日本国产| 国产精品白丝一区二区三区| 国产一区二区三区四区大秀 | 色狠狠一区二区三区| 蜜桃久久精品一区二区| 欧美在线91| 蜜臀国产一区| 国产精品日本欧美一区二区三区| 色综合视频一区二区三区日韩| 国产精品日本一区二区不卡视频| 亚洲精品成人图区| 亚洲自拍另类| 欧美激情亚洲| 婷婷成人综合| 欧美日韩一区自拍| 久久精品国产亚洲一区二区三区| 日韩毛片在线| 精品视频在线观看网站| 国产精品久久久久久久久久10秀 | 石原莉奈在线亚洲二区| 国产精品美女午夜爽爽| 91精品久久久久久久久久不卡| 日韩高清不卡一区二区| 国产日韩在线观看视频| 天堂√8在线中文| 亚洲精品视频一二三区| 国产精品xxxav免费视频| 久久精品国产99久久| 欧美一区影院| 狠狠爱成人网| 精品国产免费人成网站| 日韩国产在线一| 136国产福利精品导航网址| 国产日韩在线观看视频| 美女国产精品| 99国产精品一区二区| 国产亚洲字幕| 日韩视频中文| 免费亚洲一区| 欧美综合国产| 三级精品视频| 青青草视频一区| 成人精品视频| 亚洲国产影院| 福利片在线一区二区| 日韩午夜一区| 精品国产中文字幕第一页| 视频一区欧美精品| 久久99青青| 精品在线播放| 久久99精品久久久久久园产越南| 国产成人77亚洲精品www| 黄色日韩在线| 久久久久伊人| 蜜桃一区二区三区在线观看| 里番精品3d一二三区| 蜜臀精品一区二区三区在线观看| 久久精品天堂| 天堂va欧美ⅴa亚洲va一国产| 成人国产精品一区二区免费麻豆| 亚洲一区国产| 国产成人调教视频在线观看| 免费国产亚洲视频| 999视频精品| 岛国av在线播放| 亚洲精品一级|