国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - SpringBoot AOP方式實現多數據源切換的方法

SpringBoot AOP方式實現多數據源切換的方法

2021-04-16 13:26dianwoda Java教程

本篇文章主要介紹了SpringBoot AOP方式實現多數據源切換的方法,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

最近在做保證金余額查詢優化,在項目啟動時候需要把余額全量加載到本地緩存,因為需要全量查詢所有騎手的保證金余額,為了不影響主數據庫的性能,考慮把這個查詢走從庫。所以涉及到需要在一個項目中配置多數據源,并且能夠動態切換。經過一番摸索,完美實現動態切換,記錄一下配置方法供大家參考。

設計總體思路

Spring-Boot+AOP方式實現多數據源切換,繼承AbstractRoutingDataSource實現數據源動態的獲取,在service層使用注解指定數據源。

步驟

一、多數據源配置

在application.properties中,我們的配置是這樣的

 
?
1
 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#主數據源
druid.master.url=jdbc:mysql://url/masterdb?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull
druid.master.username=xxx
druid.master.password=123
druid.master.driver-class-name=com.mysql.jdbc.Driver
druid.master.max-wait=5000
druid.master.max-active=100
druid.master.test-on-borrow=true
druid.master.validation-query=SELECT 1
 
#從數據源
druid.slave.url=jdbc:mysql://url/slavedb?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull
druid.slave.username=xxx
druid.slave.password=123
druid.slave.driver-class-name=com.mysql.jdbc.Driver
druid.slave.max-wait=5000
druid.slave.max-active=100
druid.slave.test-on-borrow=true
druid.slave.validation-query=SELECT 1

讀取配置

 
?
1
 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<!-- master數據源 -->
<bean primary="true" id="masterdb" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
  <!-- 基本屬性 url、user、password -->
  <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
  <property name="url" value="${druid.master.url}"/>
  <property name="username" value="${druid.master.username}"/>
  <property name="password" value="${druid.master.password}"/>
  <!-- 配置初始化最大 -->
  <property name="maxActive" value="${druid.master.max-active}"/>
  <!-- 配置獲取連接等待超時的時間 -->
  <property name="maxWait" value="${druid.master.max-wait}"/>
  <property name="validationQuery" value="${druid.master.validation-query}"/>
  <property name="testOnBorrow" value="${druid.master.test-on-borrow}"/>
 
</bean>
 
<!-- slave數據源 -->
<bean primary="true" id="slavedb" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
  <!-- 基本屬性 url、user、password -->
  <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
  <property name="url" value="${druid.slave.url}"/>
  <property name="username" value="${druid.slave.username}"/>
  <property name="password" value="${druid.slave.password}"/>
 
  <!-- 配置初始化大小、最小、最大 -->
  <property name="maxActive" value="${druid.slave.max-active}"/>
  <!-- 配置獲取連接等待超時的時間 -->
  <property name="maxWait" value="${druid.slave.max-wait}"/>
  <property name="validationQuery" value="${druid.slave.validation-query}"/>
  <property name="testOnBorrow" value="${druid.slave.test-on-borrow}"/>
</bean>
 
<!-- 動態數據源,根據service接口上的注解來決定取哪個數據源 -->
<bean id="dataSource" class="datasource.DynamicDataSource">
  <property name="targetDataSources">
    <map key-type="java.lang.String">
      <entry key="slave" value-ref="slavedb"/>
      <entry key="master" value-ref="masterdb"/>
    </map>
  </property>
  <property name="defaultTargetDataSource" ref="masterdb"/>
</bean>
 
<!-- Spring JdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
  <property name="dataSource" ref="dataSource" />
</bean>
 
<!-- Spring事務管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource" />
</bean>
 
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
  <property name="transactionManager" ref="transactionManager"/>
</bean>
 
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" order="2" />
 
<!-- depositdbSqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
  <property name="mapperLocations" value="classpath*:mapper-xxdb/*Mapper*.xml" />
</bean>
 
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  <property name="basePackage" value="xxdb.mapper"/>
  <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>

二、動態數據源

spring為我們提供了AbstractRoutingDataSource,即帶路由的數據源。繼承后我們需要實現它的determineCurrentLookupKey(),該方法用于自定義實際數據源名稱的路由選擇方法,由于我們將信息保存到了ThreadLocal中,所以只需要從中拿出來即可。

 
?
1
 
2
3
4
5
6
7
8
9
10
public class DynamicDataSource extends AbstractRoutingDataSource {
  private Logger logger = LoggerFactory.getLogger(this.getClass());
 
  @Override
  protected Object determineCurrentLookupKey() {
    String dataSource = JdbcContextHolder.getDataSource();
    logger.info("數據源為{}",dataSource);
    return dataSource;
  }
}

三. 數據源動態切換類

動態數據源切換是基于AOP的,所以我們需要聲明一個AOP切面,并在切面前做數據源切換,切面完成后移除數據源名稱。

 
?
1
 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
@Aspect
@Order(1//設置AOP執行順序(需要在事務之前,否則事務只發生在默認庫中)
@Component
public class DataSourceAspect {
 
  private Logger logger = LoggerFactory.getLogger(this.getClass());
  //切點
  @Pointcut("execution(* com.xxx.service.*.*(..))")
  public void aspect() { }
 
  @Before("aspect()")
  private void before(JoinPoint point) {
    Object target = point.getTarget();
    String method = point.getSignature().getName();
    Class<?> classz = target.getClass();// 獲取目標類
    Class<?>[] parameterTypes = ((MethodSignature) point.getSignature())
        .getMethod().getParameterTypes();
    try {
      Method m = classz.getMethod(method, parameterTypes);
      if (m != null && m.isAnnotationPresent(MyDataSource.class)) {
        MyDataSource data = m.getAnnotation(MyDataSource.class);
        logger.info("method :{},datasource:{}",m.getName() ,data.value().getName());
        JdbcContextHolder.putDataSource(data.value().getName());// 數據源放到當前線程中
      }
    } catch (Exception e) {
      logger.error("get datasource error ",e);
      //默認選擇master
      JdbcContextHolder.putDataSource(DataSourceType.Master.getName());// 數據源放到當前線程中
    }
 
  }
 
  @AfterReturning("aspect()")
  public void after(JoinPoint point) {
    JdbcContextHolder.clearDataSource();
  }
}

四、數據源管理類

 
?
1
 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class JdbcContextHolder {
 
  private final static ThreadLocal<String> local = new ThreadLocal<>();
 
  public static void putDataSource(String name) {
    local.set(name);
  }
 
  public static String getDataSource() {
    return local.get();
  }
 
  public static void clearDataSource() {
    local.remove();
  }
}

五、數據源注解和枚舉

我們切換數據源時,一般都是在調用具體接口的方法前實現,所以我們定義一個方法注解,當AOP檢測到方法上有該注解時,根據注解中value對應的名稱進行切換。

 
?
1
 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyDataSource {
 
  DataSourceType value();
 
}
public enum DataSourceType {
  // 主表
  Master("master"),
  // 從表
  Slave("slave");
 
  private String name;
 
  private DataSourceType(String name) {
    this.name = name;
  }
 
  public String getName() {
    return name;
  }
 
  public void setName(String name) {
    this.name = name;
  }
}

六、切點注解

由于我們的動態數據源配置了默認庫,所以如果方法是操作默認庫的可以不需要注解,如果要操作非默認數據源,我們需要在方法上添加@MyDataSource("數據源名稱")注解,這樣就可以利用AOP實現動態切換了

 
?
1
 
2
3
4
5
6
7
8
9
10
@Component
public class xxxServiceImpl {
  @Resource
  private XxxMapperExt xxxMapperExt;
 
  @MyDataSource(value= DataSourceType.Slave)
  public List<Object> getAll(){
    return xxxMapperExt.getAll();
  }
}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:http://tech.dianwoda.com/2018/03/28/spring-boot-aopfang-shi-shi-xian-duo-shu-ju-yuan-qie-huan

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 精品久草 | jizz中国jizz女人| 亚洲成人一区二区三区 | 亚洲成人一区二区三区在线观看 | 日本视频免费观看 | 五月激情综合网 | 99久久精品免费看国产一区二区三区 | 久久久精品网站 | 日韩精品一区二区三区中文字幕 | 人人99| 欧美激情国产日韩精品一区18 | 天天操天天干天天插 | 狠狠久 | 亚洲国产中文字幕在线 | av中文在线 | a天堂在线| www.操.com| 精品国产乱码久久久久久久 | 午夜一级片 | 一级黄色片网站 | 欧美日韩在线一区二区三区 | 欧美综合一区二区三区 | 色片在线观看 | 中文字幕在线一区 | 国产成人久久精品一区二区三区 | 国产在线观看91一区二区三区 | 中文字幕在线不卡 | 免费看黄的视频网站 | 精品国产黄a∨片高清在线 欧美一级免费 | 国产成人在线视频 | 在线永久免费观看日韩a | 日韩欧美中文字幕在线视频 | 91精品国产色综合久久 | 日韩在线免费视频 | 成人av一区二区三区 | 欧美在线观看一区 | 激情国产视频 | 国产在线网站 | 成人久久久久久久 | 中国大陆高清aⅴ毛片 | 91久久极品|