成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

SpringBoot+Druid實(shí)現(xiàn)多數(shù)據(jù)源監(jiān)控及事務(wù)控制

moven_j / 2064人閱讀

   背景:一個(gè)項(xiàng)目中可能存在多數(shù)據(jù)源的情況,雖然微服務(wù)中,一般是單數(shù)據(jù)源,但是例如后臺(tái)管理這些管理接口則不適合使用微服務(wù)來
   提供接口,所以業(yè)務(wù)庫也需要共存于后臺(tái)管理項(xiàng)目,而后臺(tái)管理項(xiàng)目中則有自己本身的一個(gè)權(quán)限數(shù)據(jù)庫,則就會(huì)存在多數(shù)據(jù)源的情況。

   思路:Spring本身已經(jīng)有實(shí)現(xiàn)數(shù)據(jù)源切換的功能類,可以實(shí)現(xiàn)在項(xiàng)目運(yùn)行時(shí)根據(jù)相應(yīng)key值切換到對應(yīng)的數(shù)據(jù)源DataSource上。   
   我們只需擴(kuò)展實(shí)現(xiàn)即可。
   并結(jié)合數(shù)據(jù)源動(dòng)態(tài)切換為需要切換數(shù)據(jù)源的方法增加注解,從而實(shí)現(xiàn)對帶有注解的攔截切換。

   問題:事務(wù)控制,缺省數(shù)據(jù)源生效,而切換為第二數(shù)據(jù)源時(shí),事務(wù)的數(shù)據(jù)源默認(rèn)采用了缺省的。
         網(wǎng)上有說更改切面和事務(wù)的執(zhí)行順序,但是試驗(yàn)后并未成功。

以下是為動(dòng)態(tài)數(shù)據(jù)源切換,及缺省事務(wù)第二數(shù)據(jù)源的事務(wù)控制的實(shí)現(xiàn)方案,以springboot作為基礎(chǔ)框架。

使用druid做數(shù)據(jù)源監(jiān)控與管理
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driverClassName: com.mysql.jdbc.Driver
    druid:
        first:  #數(shù)據(jù)源1
            url: jdbc:mysql://127.0.0.01:63885/demo?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8
            username: demo
            password: demo
        rongyuan:  #數(shù)據(jù)源2
            url: jdbc:mysql://127.0.0.01:63885/demo?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8
            username: demo
            password: demo
        initial-size: 10
        max-active: 100
        min-idle: 10
        max-wait: 60000
        pool-prepared-statements: true
        max-pool-prepared-statement-per-connection-size: 20
        time-between-eviction-runs-millis: 60000
        min-evictable-idle-time-millis: 300000
        validation-query: SELECT 1 FROM DUAL
        test-while-idle: true
        test-on-borrow: false
        test-on-return: false
        stat-view-servlet:
            enabled: true
            url-pattern: /druid/*
            #login-username: admin
            #login-password: admin
        filter:
            stat:
                log-slow-sql: true
                slow-sql-millis: 1000
                merge-sql: true
            wall:
                config:
                    multi-statement-allow: true
構(gòu)建數(shù)據(jù)源及注入到動(dòng)態(tài)數(shù)據(jù)源中
package io.y.common.datasources;

import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;

/**
 * @title 
 * @author zengzp
 * @time 2018年7月25日 上午11:22:46
 * @Description 
 */
@Configuration
// 加上此注解禁用數(shù)據(jù)源自動(dòng)配置
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class DynamicDataSourceConfig {

    @Bean(name="first")
    @ConfigurationProperties("spring.datasource.druid.first")
    public DataSource firstDataSource(){
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name="rongyuan")
    @ConfigurationProperties("spring.datasource.druid.rongyuan")
    public DataSource secondDataSource(){
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @Primary
    public DynamicDataSource dataSource(@Qualifier("first")DataSource firstDataSource, @Qualifier("rongyuan")DataSource secondDataSource) {
        Map targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceNames.FIRST, firstDataSource);
        targetDataSources.put(DataSourceNames.SECOND, secondDataSource);
        return new DynamicDataSource(firstDataSource, targetDataSources);
    }
    
}
繼承spring的動(dòng)態(tài)實(shí)現(xiàn),及重寫數(shù)據(jù)源的獲取方法
package io.y.common.datasources;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;


/**
 * @title 
 * @author zengzp
 * @time 2018年7月25日 上午 10:20:31
 * @Description 
 */
public class DynamicDataSource extends AbstractRoutingDataSource {
    private static final ThreadLocal contextHolder = new ThreadLocal<>();

    public DynamicDataSource(DataSource defaultTargetDataSource, Map targetDataSources) {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        super.setTargetDataSources(new HashMap<>(targetDataSources));
        super.afterPropertiesSet();
    }

    @Override
    protected Object determineCurrentLookupKey() {
        return getDataSource();
    }

    public static void setDataSource(String dataSource) {
        contextHolder.set(dataSource);
    }

    public static String getDataSource() {
        return contextHolder.get();
    }

    public static void clearDataSource() {
        contextHolder.remove();
    }

}
定義數(shù)據(jù)源切換注解
package io.y.common.datasources.annotation;

import java.lang.annotation.*;


/**
 * @title 多數(shù)據(jù)源注解
 * @author zengzp
 * @time 2018年7月25日 下午14:50:53
 * @Description 
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {
    String name() default "";
}
定義切面,用來攔截帶注解的方法,并在方法執(zhí)行前實(shí)現(xiàn)數(shù)據(jù)源的切換
package io.y.common.datasources.aspect;

import java.lang.reflect.Method;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import io.y.common.datasources.DataSourceNames;
import io.y.common.datasources.DynamicDataSource;
import io.y.common.datasources.annotation.TargetDataSource;


/**
 * @title 多數(shù)據(jù)源切面處理類
 * @author zengzp
 * @time 2018年7月25日 下午11:56:43
 * @Description 
 */
@Aspect
@Component
@Order(0)
public class DataSourceAspect {
    protected Logger logger = LoggerFactory.getLogger(getClass());

    @Pointcut("@annotation(io.y.common.datasources.annotation.TargetDataSource)")
    public void dataSourcePointCut() {

    }

    @Before("dataSourcePointCut()")
    public void around(JoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        TargetDataSource ds = method.getAnnotation(TargetDataSource.class);
        if(ds == null){
            DynamicDataSource.setDataSource(DataSourceNames.FIRST);
            logger.debug("set datasource is " + DataSourceNames.FIRST);
        }else {
            DynamicDataSource.setDataSource(ds.name());
            logger.debug("set datasource is " + ds.name());
        }
    }
    
    @AfterReturning("dataSourcePointCut()")
    public void after(){
        DynamicDataSource.clearDataSource();
        logger.debug("clean datasource");
    }

}
數(shù)據(jù)源名稱常量類
package io.y.common.datasources;

/**
 * @title 增加多數(shù)據(jù)源,在此配置
 * @author zengzp
 * @time 2018年7月25日 下午4:55:20
 * @Description 
 */
public interface DataSourceNames {
    String FIRST = "first";
    String SECOND = "rongyuan";

}

以上已經(jīng)完成了動(dòng)態(tài)數(shù)據(jù)源的切換,只需在Service方法上加上@TargetDataScoure注解并且指定需要切換的數(shù)據(jù)源名稱,first數(shù)據(jù)源為缺省數(shù)據(jù)源。

如果使用@Transactional,缺省數(shù)據(jù)源的事務(wù)正常執(zhí)行,如果使@TargetDataScoure切換為第二數(shù)據(jù)源并執(zhí)行事務(wù)時(shí),則數(shù)據(jù)源切換失敗。

問題分析:

   大多數(shù)項(xiàng)目只需要一個(gè)事務(wù)管理器。如果存在多數(shù)據(jù)源的情況,事務(wù)管理器是否會(huì)生效,由于spingboot約定大于配置的理念,
   默認(rèn)事務(wù)管理器無需我們再聲明定義,而是默認(rèn)加載時(shí)已經(jīng)指定了其數(shù)據(jù)源,其數(shù)據(jù)源則為缺省數(shù)據(jù)源,如果執(zhí)行事務(wù)時(shí)是第二數(shù)據(jù)源,則
   還會(huì)以第一數(shù)據(jù)源做處理,這時(shí)則會(huì)異常。

第二數(shù)據(jù)源事務(wù)控制處理

定義事務(wù)管理器 并指定其對應(yīng)管理的數(shù)據(jù)源和聲明name

package io.y.common.datasources;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

/**
 * @title 多事物管理器配置
 * @author zengzp
 * @time 2018年7月25日 下午4:55:33
 * @Description 
 */
@Configuration
public class TransactionConfig {
    
    public final static String DEFAULT_TX = "defaultTx";
    
    public final static String RONGYUAN_TX = "rongyuanTx";
    
    @Bean(name=TransactionConfig.DEFAULT_TX)
    public DataSourceTransactionManager transaction(@Qualifier(DataSourceNames.FIRST)DataSource firstDataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(firstDataSource);
        return dataSourceTransactionManager;
    }
    
    @Bean(name=TransactionConfig.RONGYUAN_TX)
    public DataSourceTransactionManager rongyuanTransaction(@Qualifier(DataSourceNames.SECOND) DataSource rongyuanDataScoure){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(rongyuanDataScoure);
        return dataSourceTransactionManager;
    }

}
2.事務(wù)管理器使用
在@Transactional上指定使用哪個(gè)名稱的事務(wù)管理器
    @Override
    @Transactional(value=TransactionConfig.RONGYUAN_TX, rollbackFor=Exception.class)
    @TargetDataSource(name = "rongyuan")
    public void deleteBatch(Integer[] advertIds) {
        if (advertIds == null || advertIds.length <= 0) {
            throw new IllegalArgumentException("參數(shù)異常");
        }
        advertDao.deleteBatch(advertIds);
    }

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/76516.html

相關(guān)文章

  • SpringBoot+Mybatis配置Druid數(shù)據(jù)源

    摘要:多數(shù)據(jù)源,一般用于對接多個(gè)業(yè)務(wù)上獨(dú)立的數(shù)據(jù)庫可能異構(gòu)數(shù)據(jù)庫。這也就導(dǎo)致異構(gòu)數(shù)據(jù)庫的檢查也是類似問題。內(nèi)容略數(shù)據(jù)源多數(shù)據(jù)源,涉及到異構(gòu)數(shù)據(jù)庫,必須明確指定,否則的轉(zhuǎn)換出錯(cuò)取值內(nèi)容可參考初始連接數(shù)最大連接池?cái)?shù)量。 開篇之前,說一句題外話。多數(shù)據(jù)源和動(dòng)態(tài)數(shù)據(jù)源的區(qū)別。 多數(shù)據(jù)源,一般用于對接多個(gè)業(yè)務(wù)上獨(dú)立的數(shù)據(jù)庫(可能異構(gòu)數(shù)據(jù)庫)。 動(dòng)態(tài)數(shù)據(jù)源,一般用于大型應(yīng)用對數(shù)據(jù)切分。 配置參考 如...

    Songlcy 評論0 收藏0
  • 單手?jǐn)]了個(gè)springboot+mybatis+druid

    摘要:配置想想,我們需要哪些數(shù)據(jù)庫要用到,數(shù)據(jù)庫連接池要用到橋接器要用到,因此要倉庫點(diǎn)我去倉庫中找到搜索這些加進(jìn)去。 本文旨在用最通俗的語言講述最枯燥的基本知識(shí) 最近身邊的程序員掀起了學(xué)習(xí)springboot的熱潮,說什么學(xué)會(huì)了springboot在大街上就可以橫著走、什么有了springboot媽媽再也不擔(dān)心我的編程了、什么BAT都喜歡的框架...聽得作者那個(gè)心癢癢的,于是找了個(gè)時(shí)間,下載...

    adie 評論0 收藏0
  • springboot系列】springboot整合獨(dú)立模塊Druid + mybatis-plus

    摘要:申請連接時(shí)執(zhí)行檢測連接是否有效,做了這個(gè)配置會(huì)降低性能。作者在版本中使用,通過監(jiān)控界面發(fā)現(xiàn)有緩存命中率記錄,該應(yīng)該是支持。允許和不允許單條語句返回多個(gè)數(shù)據(jù)集取決于驅(qū)動(dòng)需求使用列標(biāo)簽代替列名稱。需要驅(qū)動(dòng)器支持。將自動(dòng)映射所有復(fù)雜的結(jié)果。 項(xiàng)目github地址:https://github.com/5-Ason/aso... 具體可看 ./db/db-mysql 模塊 本文主要實(shí)現(xiàn)的是對...

    RobinTang 評論0 收藏0

發(fā)表評論

0條評論

moven_j

|高級講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<