成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

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

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

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

多數(shù)據(jù)源切換是為了滿足什么業(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)滿足需求,當(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中既需要查詢數(shù)據(jù)庫(kù)A,又需要查詢數(shù)據(jù)庫(kù)B,而且兩者都希望用entity(Mybatis中用于與表結(jié)構(gòu)保持一直的bean)來(lái)接收查詢結(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類開(kāi)啟Spring事務(wù),事務(wù)的意思是指具有原子性的一個(gè)操作集合(本人理解),該事務(wù)做什么事在dao層的配置文件里配置,后面會(huì)講。 @Service //表明為Service類,使用Component也行,Spring在啟動(dòng)時(shí)會(huì)掃描該類將該類所需要的bean全部構(gòu)建出來(lái)以供使用 @TargetDataSource(name = 'dataSource1') //重點(diǎn),自定義的AOP注解,指定該TestService1類下的所有public方法都使用數(shù)據(jù)源dataSource1 class TestService1{ public void queryAllUser(){ UserMapper userMapper = new UserMapper() userMapper.queryAllUser(); System.out.println('使用數(shù)據(jù)源dataSource1查詢用戶信息') } } @Transactional @Service @TargetDataSource(name = 'dataSource2') class TestService2{ public void queryAllBook(){ BookMapper bookMapper = new BookMapper() bookMapper.queryAllBook(); System.out.println('使用數(shù)據(jù)源dataSource2查詢書(shū)籍信息') } }

在每一個(gè)需要切換數(shù)據(jù)源的Service層使用TargetDataSource(name= “***”)即可指定當(dāng)前線程的數(shù)據(jù)源,當(dāng)然別忘記@Transactional事務(wù)的添加,該事務(wù)用于Mybatis查詢數(shù)據(jù)時(shí)去獲取當(dāng)前線程的數(shù)據(jù)源為哪一個(gè)。如此在controller中正常調(diào)用Service中的方法就行了,如果需要查詢兩個(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查詢數(shù)據(jù)源1中的所有用戶') val allBook = testService2.queryAllBook('33287') println('使用TestService2查詢數(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 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實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)源選擇

配置文件中添加

<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> <!-- 默認(rèn)使用dataSource1的數(shù)據(jù)源 --> <property name='defaultTargetDataSource' ref='dataSource1' /> </bean>

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

類一:

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

類二:

public class DataSourceHolder { //線程本地環(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ù)用戶定義的規(guī)則選擇當(dāng)前的數(shù)據(jù)源,這樣我們可以在執(zhí)行查詢之前,設(shè)置使用的數(shù)據(jù)源。實(shí)現(xiàn)可動(dòng)態(tài)路由的數(shù)據(jù)源,在每次數(shù)據(jù)庫(kù)查詢操作前執(zhí)行。它的抽象方法 determineCurrentLookupKey() 決定使用哪個(gè)數(shù)據(jù)源。以上完成數(shù)據(jù)庫(kù)操作之前的數(shù)據(jù)源選擇,使用的是DataSourceHolder.getDataSoure();

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

在配置文件中添加

<!-- 定義事務(wù)管理器(聲明式的事務(wù)) --> <bean class='org.springframework.jdbc.datasource.DataSourceTransactionManager'> <property name='dataSource' ref='dataSource' /> </bean> <!-- 將所有具有@Transactional注解的Bean自動(dòng)配置為聲明式事務(wù)支持 --> <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中使用的數(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 自定義的切面類實(shí)現(xiàn)數(shù)據(jù)源切換--> <bean /> <!--配置AOP --> <aop:config> <!--配置切點(diǎn)表達(dá)式 定義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包下創(chuàng)建DataSourceExchange類實(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為查詢數(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注解類

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/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> <!-- 默認(rèn)使用dataSource1的數(shù)據(jù)源 --> <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> <!--配置可以批量執(zhí)行的sqlSession --> <!--配置切面的bean --> <bean /> <!--配置AOP --> <aop:config> <!--配置切點(diǎn)表達(dá)式 --> <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>

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

標(biāo)簽: Spring
相關(guān)文章:
成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久
成人午夜av影视| 欧美a级一区| 欧美一卡二卡在线| 午夜日韩在线观看| 欧美午夜不卡| 中文字幕精品一区二区精品绿巨人 | 国产精品资源| 国产精品家庭影院| 午夜视频一区| 国产精品色一区二区三区| 欧美伊人久久| 欧美激情一区二区三区蜜桃视频| 91在线视频官网| 26uuu成人网一区二区三区| 国产成人在线网站| 91精品国产综合久久精品图片| 免播放器亚洲一区| 在线亚洲高清视频| 国产乱对白刺激视频不卡| 欧美一区二区三区婷婷月色 | 国产亚洲精品久久飘花| 一区二区三区免费网站| 亚洲欧美卡通另类91av| 亚洲一卡二卡三卡四卡| 国产精品欧美日韩一区| 亚洲国产成人av网| 色八戒一区二区三区| 日韩av一区二区三区| 91久久精品一区二区三| 韩国精品主播一区二区在线观看| 欧美亚洲一区三区| 国产黄人亚洲片| 精品伦理精品一区| 欧美视频成人| 一区二区三区欧美亚洲| 色综合久久久久网| 美国毛片一区二区三区| a在线欧美一区| 国产精品久久久久影视| 99成人在线| 日本成人在线电影网| 精品视频全国免费看| 粉嫩欧美一区二区三区高清影视 | 国产麻豆日韩欧美久久| 精品久久一区二区三区| 午夜亚洲福利| 亚洲综合在线五月| 欧美在线一区二区三区| 成人白浆超碰人人人人| 亚洲欧美在线另类| 色呦呦日韩精品| 国产精品一区二区黑丝| 久久久久久久国产精品影院| 韩日欧美一区| 天天综合日日夜夜精品| 欧美日韩国产在线观看| a4yy欧美一区二区三区| 国产精品伦理在线| 亚洲视频1区| 黑人巨大精品欧美黑白配亚洲| 久久综合九色综合久久久精品综合| 好看的亚洲午夜视频在线| 亚洲va国产va欧美va观看| 欧美日韩一区二区三区免费看| 成人高清在线视频| 中文字幕一区二区三区在线不卡 | 久久精品国产久精国产| 久久久亚洲精品石原莉奈| 99精品国产一区二区青青牛奶| 热久久一区二区| 精品久久一区二区| 亚洲开发第一视频在线播放| 精品中文av资源站在线观看| 国产三级欧美三级日产三级99| 亚洲永久免费| av在线一区二区| 亚洲欧美偷拍三级| 欧美精三区欧美精三区| 欧美日韩影院| 日韩精品电影在线观看| 久久亚洲免费视频| 午夜在线观看免费一区| 豆国产96在线|亚洲| 亚洲美女区一区| 欧美一区二区网站| av成人黄色| 白白色亚洲国产精品| 亚洲电影中文字幕在线观看| 日韩丝袜情趣美女图片| 在线亚洲欧美| 国产精品香蕉一区二区三区| 国产精品国产三级国产aⅴ中文| 色婷婷亚洲一区二区三区| 99精品国产热久久91蜜凸| 亚洲va欧美va国产va天堂影院| 欧美va天堂va视频va在线| 亚洲永久免费| 欧美~级网站不卡| 极品少妇一区二区| 亚洲人成小说网站色在线| 日韩欧美亚洲国产另类 | 蜜桃av一区| 91影院在线观看| 免费在线看成人av| 亚洲日韩欧美一区二区在线| 日韩片之四级片| 老鸭窝91久久精品色噜噜导演| 99re这里都是精品| 蜜臀av在线播放一区二区三区| 久久你懂得1024| 欧美在线999| 亚洲美女少妇无套啪啪呻吟| 处破女av一区二区| 日韩在线播放一区二区| 国产精品日韩成人| 日韩午夜三级在线| 91久久线看在观草草青青| 亚洲高清久久| 北条麻妃一区二区三区| 免费观看日韩av| 亚洲乱码国产乱码精品精98午夜| 精品日韩欧美在线| 欧美日韩一区二区在线观看| 亚洲自啪免费| 欧美黄色大片网站| 国产盗摄精品一区二区三区在线| 五月婷婷综合在线| 国产精品女同互慰在线看| 日韩欧美激情四射| 欧美视频在线观看一区| 午夜在线视频观看日韩17c| 亚洲午夜激情在线| 成人国产视频在线观看| 美女脱光内衣内裤视频久久网站 | 成人av免费在线观看| 精品在线观看视频| 亚洲黄一区二区三区| 国产喷白浆一区二区三区| 日韩一区二区视频| 在线观看不卡一区| 久久性色av| 国产精品免费一区二区三区观看| 欧美福利影院| 国产福利一区二区三区在线视频| 日韩在线a电影| 亚洲小少妇裸体bbw| 日韩毛片精品高清免费| 国产无人区一区二区三区| 欧美成人一区二区三区在线观看| 欧美视频中文一区二区三区在线观看| 国产农村妇女精品一二区 | 亚洲特级毛片| 欧美激情1区| 91一区在线观看| 99国产欧美另类久久久精品 | 欧美精品观看| 欧美精品亚洲精品| 欧美阿v一级看视频| 成av人片一区二区| 成人性生交大片免费看视频在线 | 亚洲五码中文字幕| 亚洲欧美在线视频| 国产精品每日更新在线播放网址 | 欧美三级在线| 欧美精品尤物在线| 欧美久久久久久久| 91麻豆精品在线观看| 99久久婷婷国产精品综合| 99vv1com这只有精品| 99久久国产综合精品色伊| 99免费精品视频| 91麻豆国产自产在线观看| 色综合色综合色综合色综合色综合| 91社区在线播放| 欧美激情第六页| 亚洲性色视频| 日韩亚洲视频在线| 国产乱码精品| 久久久福利视频| 在线看日韩精品电影| 欧美日韩成人高清| 日韩午夜在线观看视频| 久久人人超碰精品| 国产偷v国产偷v亚洲高清| 中文成人av在线| 亚洲欧美偷拍卡通变态| 亚洲午夜一二三区视频| 日韩和的一区二区| 老司机精品视频导航| 国产精品一二三区| 99视频在线观看一区三区| 欧美日本韩国一区二区三区| 亚洲欧洲日本mm| 亚洲影视在线| 欧美日韩中字一区| 337p日本欧洲亚洲大胆色噜噜| 久久精品水蜜桃av综合天堂| 国产午夜亚洲精品理论片色戒| 国产精品国产三级国产aⅴ原创| 一区二区三区在线免费观看|