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

SpringBoot AOP方式實現(xiàn)多數(shù)據(jù)源切換的方法

 更新時間:2018年03月29日 10:02:19   投稿:zx  
本篇文章主要介紹了SpringBoot AOP方式實現(xiàn)多數(shù)據(jù)源切換的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

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

設計總體思路

Spring-Boot+AOP方式實現(xiàn)多數(shù)據(jù)源切換,繼承AbstractRoutingDataSource實現(xiàn)數(shù)據(jù)源動態(tài)的獲取,在service層使用注解指定數(shù)據(jù)源。

步驟

一、多數(shù)據(jù)源配置

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

#主數(shù)據(jù)源
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

#從數(shù)據(jù)源
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

讀取配置

<!-- master數(shù)據(jù)源 -->
<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數(shù)據(jù)源 -->
<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>

<!-- 動態(tài)數(shù)據(jù)源,根據(jù)service接口上的注解來決定取哪個數(shù)據(jù)源 -->
<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>

二、動態(tài)數(shù)據(jù)源

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

public class DynamicDataSource extends AbstractRoutingDataSource {
  private Logger logger = LoggerFactory.getLogger(this.getClass());

  @Override
  protected Object determineCurrentLookupKey() {
    String dataSource = JdbcContextHolder.getDataSource();
    logger.info("數(shù)據(jù)源為{}",dataSource);
    return dataSource;
  }
}

三. 數(shù)據(jù)源動態(tài)切換類

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

@Aspect
@Order(1)  //設置AOP執(zhí)行順序(需要在事務之前,否則事務只發(fā)生在默認庫中)
@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());// 數(shù)據(jù)源放到當前線程中
      }
    } catch (Exception e) {
      logger.error("get datasource error ",e);
      //默認選擇master
      JdbcContextHolder.putDataSource(DataSourceType.Master.getName());// 數(shù)據(jù)源放到當前線程中
    }

  }

  @AfterReturning("aspect()")
  public void after(JoinPoint point) {
    JdbcContextHolder.clearDataSource();
  }
}

四、數(shù)據(jù)源管理類

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();
  }
}

五、數(shù)據(jù)源注解和枚舉

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

@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;
  }
}

六、切點注解

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

@Component
public class xxxServiceImpl {
  @Resource
  private XxxMapperExt xxxMapperExt;

  @MyDataSource(value= DataSourceType.Slave)
  public List<Object> getAll(){
    return xxxMapperExt.getAll();
  }
}

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • Java面試題沖刺第十天--MyBatis2

    Java面試題沖刺第十天--MyBatis2

    這篇文章主要為大家分享了最有價值的三道MyBatis框架面試題,涵蓋內(nèi)容全面,包括數(shù)據(jù)結(jié)構(gòu)和算法相關的題目、經(jīng)典面試編程題等,感興趣的小伙伴們可以參考一下
    2021-07-07
  • Spring Cloud 2023 新特性支持同步網(wǎng)關

    Spring Cloud 2023 新特性支持同步網(wǎng)關

    這篇文章主要為大家介紹了Spring Cloud 2023 新特性支持同步網(wǎng)關講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-10-10
  • SpringBoot超詳細講解自動配置原理

    SpringBoot超詳細講解自動配置原理

    在進行項目編寫前,我們還需要知道一個東西,就是SpringBoot對我們的SpringMVC還做了哪些配置,包括如何擴展,如何定制,只有把這些都搞清楚了,我們在之后使用才會更加得心應手
    2022-06-06
  • Java 進行時間處理的步驟

    Java 進行時間處理的步驟

    時間處理是常見的需求,本文將講述Java語言如何進行時間處理,感興趣的朋友可以了解下
    2021-05-05
  • java僅用30行代碼就實現(xiàn)了視頻轉(zhuǎn)音頻的批量轉(zhuǎn)換

    java僅用30行代碼就實現(xiàn)了視頻轉(zhuǎn)音頻的批量轉(zhuǎn)換

    這篇文章主要介紹了java僅用30行代碼就實現(xiàn)了視頻轉(zhuǎn)音頻的批量轉(zhuǎn)換,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-04-04
  • SpringBoot中的Profile多環(huán)境配置方法

    SpringBoot中的Profile多環(huán)境配置方法

    這篇文章主要介紹了SpringBoot中的Profile多環(huán)境配置,SpringBoot提供了兩種多環(huán)境配置的方式,分別是使用profile文件進行多環(huán)境配置以及使用@Profile注解進行多環(huán)境配置,需要的朋友可以參考下
    2023-01-01
  • springboot controller參數(shù)注入方式

    springboot controller參數(shù)注入方式

    這篇文章主要介紹了springboot controller參數(shù)注入方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • SpringBoot中API接口參數(shù)獲取方式小結(jié)

    SpringBoot中API接口參數(shù)獲取方式小結(jié)

    在Spring Boot中,API接口參數(shù)可以通過多種方式獲取,具體取決于你定義的API接口參數(shù)類型(如路徑參數(shù)、查詢參數(shù)、請求體參數(shù)、請求頭等),本文給大家就介紹了一些常見的參數(shù)獲取方式,需要的朋友可以參考下
    2024-06-06
  • java 單元測試 對h2數(shù)據(jù)庫數(shù)據(jù)清理方式

    java 單元測試 對h2數(shù)據(jù)庫數(shù)據(jù)清理方式

    這篇文章主要介紹了java 單元測試 對h2數(shù)據(jù)庫數(shù)據(jù)清理方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • 詳解SpringBoot如何自定義啟動畫面

    詳解SpringBoot如何自定義啟動畫面

    當我們在啟動SpringBoot項目時候會在控制臺上看到一些單調(diào)的圖案,有些朋友覺得這些圖案很單調(diào),那我們是否可以自定義啟動畫面呢,接下來小編就給大家介紹一下SpringBoot是如何實現(xiàn)自定義啟動畫面,感興趣的同學跟著小編一起來看看吧
    2023-07-07

最新評論