最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

druid多數(shù)據(jù)源配置+Datasurce動(dòng)態(tài)切換方式

 更新時(shí)間:2021年09月07日 11:12:44   作者:Mandsence  
這篇文章主要介紹了druid多數(shù)據(jù)源配置+Datasurce動(dòng)態(tài)切換方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

druid多數(shù)據(jù)源配置+Datasurce動(dòng)態(tài)切換

AbstractRoutingDataSource 數(shù)據(jù)源動(dòng)態(tài)切換

spring 使用AbstractRoutingDataSource自定義動(dòng)態(tài)數(shù)據(jù)源時(shí)的事務(wù)處理, 需要繼承spring的AbstractRoutingDataSource定義自己的動(dòng)態(tài)數(shù)據(jù)源,可以根據(jù)需要?jiǎng)討B(tài)的切換不同數(shù)據(jù)庫的數(shù)據(jù)源,使用起來非常方便。

public class ChooseDataSource extends AbstractRoutingDataSource {
 /**
  * 獲取與數(shù)據(jù)源相關(guān)的key
  * 此key是Map<String,DataSource> resolvedDataSources 中與數(shù)據(jù)源綁定的key值
  * 在通過determineTargetDataSource獲取目標(biāo)數(shù)據(jù)源時(shí)使用
  */
 @Override
 protected Object determineCurrentLookupKey() {
  return RouteHolder.getRouteKey();
 }
}

通過容器RouteHolder存儲(chǔ)當(dāng)前線程使用的數(shù)據(jù)源的key

/**
 * 保存當(dāng)前線程數(shù)據(jù)源的key
 */
public class RouteHolder {
 private static ThreadLocal<String> routeKey = new ThreadLocal<String>();
 
 /**
  * 獲取當(dāng)前線程的數(shù)據(jù)源路由的key
  * @return
  */
 public static String getRouteKey()
 {
  String key = routeKey.get();
  return key;
 }
 /**
  * 綁定當(dāng)前線程數(shù)據(jù)源路由的key
  * 在使用完成之后,必須調(diào)用removeRouteKey()方法刪除
  * @param key
  */
 public static void  setRouteKey(String key)
 {
  routeKey.set(key);
 }
 
 /**
  * 刪除與當(dāng)前線程綁定的數(shù)據(jù)源路由的key
  */
 public static void removeRouteKey()
 {
  routeKey.remove();
 }
}

使用spring 的aop編程在業(yè)務(wù)邏輯方法運(yùn)行前將當(dāng)前方法使用數(shù)據(jù)源的key從業(yè)務(wù)邏輯方法上自定義注解@DataSource中解析數(shù)據(jù)源key并添加到RouteHolder中

/**
 * 執(zhí)行dao方法之前的切面
 * 獲取datasource對(duì)象之前往RouteHolder中指定當(dāng)前線程數(shù)據(jù)源路由的key
 *
 */
public class DataSourceAspect {
    /**
     * 在dao層方法之前獲取datasource對(duì)象之前在切面中指定當(dāng)前線程數(shù)據(jù)源路由的key
     */
    public void before(JoinPoint point)
    {
        Object target = point.getTarget();
        String method = point.getSignature().getName();
        Class<?>[] classz = target.getClass().getInterfaces();
        Class<?>[] parameterTypes = ((MethodSignature) point.getSignature())
                .getMethod().getParameterTypes();
        try {
            if(classz != null && classz.length > 0) {
            Method m = classz[0].getMethod(method, parameterTypes);
            if (m != null && m.isAnnotationPresent(DataSource.class)) {
                DataSource data = m.getAnnotation(DataSource.class);
                RouteHolder.setRouteKey(data.value());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

解釋:

DataSourceAspect 這個(gè)切面類,應(yīng)該針對(duì)的被代理類應(yīng)該是service的實(shí)現(xiàn)類(serviceImpl),因?yàn)閐ao層用的mybatis只有一個(gè)dao層的接口,所以放在service上做處理比較好。

業(yè)務(wù)邏輯方法

@Named("userService")
public class UserService 
{
 @Inject
 private UserDao userDao;
 
 @DataSource("master")
 @Transactional(propagation=Propagation.REQUIRED)
 public void updatePasswd(int userid,String passwd)
 {
  User user = new User();
  user.setUserid(userid);
  user.setPassword(passwd);
  userDao.updatePassword(user);
 }
 @DataSource("slave")
 @Transactional(propagation=Propagation.REQUIRED)
 public User getUser(int userid)
 {
  User user = userDao.getUserById(userid);
  System.out.println("username------:"+user.getUsername());
  return user;
 }
}

注解類

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
 * RUNTIME
 * 編譯器將把注釋記錄在類文件中,在運(yùn)行時(shí) VM 將保留注釋,因此可以反射性地讀取。
 * @author jiangxm
 *
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataSource {
    String value();
}

spring的配置文件

<bean id="dataSource" class="com.westone.datasource.DbRouteDataSource">
  <property name="targetDataSources">
    <map>
       <!-- write -->
       <entry key="master" value-ref="master"></entry>
       <!-- read -->
       <entry key="slave" value-ref="slave"></entry>
    </map>
  </property> 
 </bean> 
 
 <bean id="master" class="org.apache.commons.dbcp.BasicDataSource">  
        <property name="driverClassName" value="${jdbc.driverclass}" />  
        <property name="url" value="${jdbc.masterurl}" />  
        <property name="username" value="${jdbc.username}" />  
        <property name="password" value="${jdbc.password}" />  
        <property name="maxActive" value="${jdbc.maxActive}"></property>  
        <property name="maxIdle" value="${jdbc.maxIdle}"></property>  
        <property name="maxWait" value="${jdbc.maxWait}"></property>  
    </bean>  
    
    <bean id="slave" class="org.apache.commons.dbcp.BasicDataSource">  
        <property name="driverClassName" value="${jdbc.driverclass}" />  
        <property name="url" value="${jdbc.slaveurl}" />  
        <property name="username" value="${jdbc.username}" />  
        <property name="password" value="${jdbc.password}" />  
        <property name="maxActive" value="${jdbc.maxActive}"></property>  
        <property name="maxIdle" value="${jdbc.maxIdle}"></property>  
        <property name="maxWait" value="${jdbc.maxWait}"></property>  
    </bean>    
      
    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate" >  
        <constructor-arg index="0" ref="sqlSessionFactory" />
    </bean>
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  
        <property name="configLocation" value="classpath:config/mybatis/mybatis.cfg.xml"></property>  
        <property name="dataSource" ref="dataSource" />  
    </bean> 
    
    <!--  配置mapper的映射掃描器 根據(jù)包中定義的接口自動(dòng)生成dao的實(shí)現(xiàn)類-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
      <property name="basePackage" value="com.westone.dao"></property>
    </bean>   
   
   <!-- 為業(yè)務(wù)邏輯層的方法解析@DataSource注解  為當(dāng)前線程的routeholder注入數(shù)據(jù)源key -->
    <bean id="aspectBean" class="com.westone.datasource.aspect.DataSourceAspect"></bean>
    
    <aop:config>
     <aop:aspect id="dataSourceAspect" ref="aspectBean">
         <aop:pointcut id="dataSourcePoint" expression="execution(public * com.westone.service.*.*(..))" />
         <aop:before method="beforeDaoMethod" pointcut-ref="dataSourcePoint"/>
     </aop:aspect>
    </aop:config>   
   
    <!-- 事務(wù)管理器配置 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
        <property name="dataSource" ref="dataSource" />  
    </bean> 
 <!-- 開啟事務(wù)注解驅(qū)動(dòng)    在業(yè)務(wù)邏輯層上使用@Transactional 注解 為業(yè)務(wù)邏輯層管理事務(wù)-->  
    <tx:annotation-driven  transaction-manager="transactionManager"/>

事務(wù)管理配置一定要配置在往RouteHolder中注入數(shù)據(jù)源key之前 否則會(huì)報(bào)

Could not open JDBC Connection for transaction; nested exception is java.lang.IllegalStateException: Cannot determine target DataSource for lookup key [null] 找不到數(shù)據(jù)源錯(cuò)誤。

由此就可以根據(jù)方法上的@DataSource(“master”) 注解配置不同的數(shù)據(jù)源key 使用動(dòng)態(tài)數(shù)據(jù)源。

解釋:

java.lang.reflect.Method.getAnnotation(Class annotationClass)

參數(shù):

annotationClass - Class對(duì)象對(duì)相應(yīng)的注解類型,比如Datasource.class 。

返回值:

如果存在于此元素,則返回該元素注解指定的注解對(duì)象,否則返回為null

例子

import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
public class MethodDemo {
   public static void main(String[] args) {
      Method[] methods = SampleClass.class.getMethods();
      Annotation annotation = methods[0].getAnnotation(CustomAnnotation.class);
      if(annotation instanceof CustomAnnotation){
         CustomAnnotation customAnnotation = (CustomAnnotation) annotation;
         System.out.println("name: " + customAnnotation.name());
         System.out.println("value: " + customAnnotation.value());
      }
   }
}
@CustomAnnotation(name="SampleClass",  value = "Sample Class Annotation")
class SampleClass {
   private String sampleField;
   @CustomAnnotation(name="getSampleMethod",  value = "Sample Method Annotation")
   public String getSampleField() {
      return sampleField;
   }
   public void setSampleField(String sampleField) {
      this.sampleField = sampleField;
   } 
}
@Retention(RetentionPolicy.RUNTIME)
@interface CustomAnnotation {
   public String name();
   public String value();
}

編譯并運(yùn)行上面的程序,這將產(chǎn)生以下結(jié)果

-name: getSampleMethod

value: Sample Method Annotation

getInterfaces()

能夠獲得這個(gè)對(duì)象所實(shí)現(xiàn)的接口

配置多數(shù)據(jù)源并實(shí)現(xiàn)Druid自動(dòng)切換

Spring Boot配置多數(shù)據(jù)源

配置yml文件

這里并沒有對(duì)spring.datasource配置數(shù)據(jù)源,因?yàn)樵黾有聰?shù)據(jù)源后,系統(tǒng)會(huì)覆蓋由spring.datasource自動(dòng)配置的內(nèi)容。

這里自定義了兩個(gè)數(shù)據(jù)源spring.datasource.cmmi和spring.datasource.zentao

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    base:
      type: com.alibaba.druid.pool.DruidDataSource
      driver-class-name: com.mysql.cj.jdbc.Driver
      initialize: true #指定初始化數(shù)據(jù)源,是否用data.sql來初始化,默認(rèn): true
      name: cmmi
      url: jdbc:mysql://127.0.0.1:3306/cmmi?useUnicode=true&characterEncoding=utf-8&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&zeroDateTimeBehavior=convertToNull
      username: root
      password: root
    zentao:
      type: com.alibaba.druid.pool.DruidDataSource
      driver-class-name: com.mysql.cj.jdbc.Driver
      initialize: true
      name: zentaopro
      url: jdbc:mysql://127.0.0.1:3306/zentaopro?useUnicode=true&characterEncoding=utf-8&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&zeroDateTimeBehavior=convertToNull
      username: root
      password: root

主數(shù)據(jù)源配置

注意,配置類需要對(duì)DataSource、DataSourceTransactionManager、SqlSessionFactory 、SqlSessionTemplate四個(gè)數(shù)據(jù)項(xiàng)進(jìn)行配置;DataSource類型需要引入javax.sql.DataSource;當(dāng)系統(tǒng)中有多個(gè)數(shù)據(jù)源時(shí),必須有一個(gè)數(shù)據(jù)源為主數(shù)據(jù)源,使用@Primary修飾。

@MapperScan對(duì)指定dao包建立映射,確保在多個(gè)數(shù)據(jù)源下,自動(dòng)選擇合適的數(shù)據(jù)源,而在service層里不需要做特殊說明。

@Configuration
@MapperScan(basePackages = "cmmi.dao.base", sqlSessionTemplateRef = "baseSqlSessionTemplate")
public class BaseDataSourceConfig {
    @Bean(name = "baseDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.base")
    @Primary
    public DataSource setDataSource() {
        return DataSourceBuilder.create().build();
    }
    @Bean(name = "baseTransactionManager")
    @Primary
    public DataSourceTransactionManager setTransactionManager(@Qualifier("baseDataSource") DataSource dataSource) {
        return new DruidDataSource();
    }
    @Bean(name = "baseSqlSessionFactory")
    @Primary
    public SqlSessionFactory setSqlSessionFactory(@Qualifier("baseDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/base/*.xml"));
        return bean.getObject();
    }
    @Bean(name = "baseSqlSessionTemplate")
    @Primary
    public SqlSessionTemplate setSqlSessionTemplate(@Qualifier("baseSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

從數(shù)據(jù)源配置

@Configuration
@MapperScan(basePackages = "cmmi.dao.zentao", sqlSessionTemplateRef = "zentaoSqlSessionTemplate")
public class ZentaoDataSourceConfig {
    @Bean(name = "zentaoDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.zentao")
    public DataSource setDataSource() {
        return new DruidDataSource();
    }
    @Bean(name = "zentaoTransactionManager")
    public DataSourceTransactionManager setTransactionManager(@Qualifier("zentaoDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
    @Bean(name = "zentaoSqlSessionFactory")
    public SqlSessionFactory setSqlSessionFactory(@Qualifier("zentaoDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/zentao/*.xml"));
        return bean.getObject();
    }
    @Bean(name = "zentaoSqlSessionTemplate")
    public SqlSessionTemplate setSqlSessionTemplate(@Qualifier("zentaoSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

使用dao

這里只需要正常使用dao就可以了,spring會(huì)根據(jù)數(shù)據(jù)源配置的映射自動(dòng)選擇相應(yīng)數(shù)據(jù)源,而不需要在service做特殊說明。

@Service
public class TestService {
    private final ZtUserMapper ztUserMapper;
    private final LevelDic levelDic;
    @Autowired
    public TestService(ZtUserMapper ztUserMapper, LevelDic levelDic) {
        this.ztUserMapper = ztUserMapper;
        this.levelDic = levelDic;
    }
    public void test() {
        ztUserMapper.selectByPrimaryKey(1);
        levelDic.setDicId(new Integer(1).byteValue());
    }
}

日志

o.a.c.c.C.[Tomcat].[localhost].[/cmmi] : Initializing Spring FrameworkServlet ‘dispatcherServlet'
o.s.web.servlet.DispatcherServlet : FrameworkServlet ‘dispatcherServlet': initialization started
o.s.web.servlet.DispatcherServlet : FrameworkServlet ‘dispatcherServlet': initialization completed in 23 ms
com.alibaba.druid.pool.DruidDataSource : {dataSource-1,cmmi} inited
com.alibaba.druid.pool.DruidDataSource : {dataSource-2,zentaopro} inited

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 服務(wù)性能優(yōu)化之mybatis-plus開啟與關(guān)閉SQL日志打印方法

    服務(wù)性能優(yōu)化之mybatis-plus開啟與關(guān)閉SQL日志打印方法

    這篇文章主要介紹了在Mybatis-plus中開啟和關(guān)閉控制臺(tái)SQL日志打印,在`application.properties`文件中,可以通過配置來實(shí)現(xiàn)SQL日志的開啟和關(guān)閉,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-12-12
  • java對(duì)ArrayList排序代碼示例

    java對(duì)ArrayList排序代碼示例

    本文通過代碼示例給大家介紹java對(duì)arraylist排序,代碼簡(jiǎn)潔易懂,感興趣的朋友一起學(xué)習(xí)吧
    2015-11-11
  • SpringBoot事務(wù)鉤子函數(shù)的使用方式

    SpringBoot事務(wù)鉤子函數(shù)的使用方式

    本文介紹了SpringBoot中事務(wù)鉤子函數(shù)的使用方式,包括常見場(chǎng)景、使用方式等,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-11-11
  • SpringBoot如何整合Springsecurity實(shí)現(xiàn)數(shù)據(jù)庫登錄及權(quán)限控制

    SpringBoot如何整合Springsecurity實(shí)現(xiàn)數(shù)據(jù)庫登錄及權(quán)限控制

    這篇文章主要給大家介紹了關(guān)于SpringBoot如何整合Springsecurity實(shí)現(xiàn)數(shù)據(jù)庫登錄及權(quán)限控制的相關(guān)資料,文中通過圖文以及實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2022-01-01
  • IDEA的Project無法正常顯示的問題解決

    IDEA的Project無法正常顯示的問題解決

    本文主要介紹了IDEA的Project無法正常顯示的問題解決,文中通過圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-02-02
  • Java常用HASH算法總結(jié)【經(jīng)典實(shí)例】

    Java常用HASH算法總結(jié)【經(jīng)典實(shí)例】

    這篇文章主要介紹了Java常用HASH算法,結(jié)合實(shí)例形式總結(jié)分析了Java常用的Hash算法,包括加法hash、旋轉(zhuǎn)hash、FNV算法、RS算法hash、PJW算法、ELF算法、BKDR算法、SDBM算法、DJB算法、DEK算法、AP算法等,需要的朋友可以參考下
    2017-09-09
  • Spring?Boot?3.x?集成?Feign的詳細(xì)過程

    Spring?Boot?3.x?集成?Feign的詳細(xì)過程

    本文闡述了如何在SpringBoot3.x中集成Feign,以實(shí)現(xiàn)微服務(wù)之間的調(diào)用,主要步驟包括:搭建chain-common服務(wù),創(chuàng)建chain-starter/chain-feign-starter服務(wù),集成Feign到chain-system和chain-iot-channel服務(wù),配置Feign,感興趣的朋友一起看看吧
    2024-09-09
  • SpringBoot配置mybatis駝峰命名規(guī)則自動(dòng)轉(zhuǎn)換的實(shí)現(xiàn)

    SpringBoot配置mybatis駝峰命名規(guī)則自動(dòng)轉(zhuǎn)換的實(shí)現(xiàn)

    這篇文章主要介紹了SpringBoot配置mybatis駝峰命名規(guī)則自動(dòng)轉(zhuǎn)換的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • 使用cmd根據(jù)WSDL網(wǎng)址生成java客戶端代碼的實(shí)現(xiàn)

    使用cmd根據(jù)WSDL網(wǎng)址生成java客戶端代碼的實(shí)現(xiàn)

    這篇文章主要介紹了使用cmd根據(jù)WSDL網(wǎng)址生成java客戶端代碼的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-03-03
  • java實(shí)現(xiàn)學(xué)生成績(jī)檔案管理系統(tǒng)

    java實(shí)現(xiàn)學(xué)生成績(jī)檔案管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)學(xué)生成績(jī)檔案管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-07-07

最新評(píng)論

巴彦县| 清新县| 富源县| 保德县| 方山县| 威宁| 文化| 五寨县| 聂荣县| 资源县| 德安县| 芮城县| 商南县| 崇阳县| 育儿| 乡城县| 建昌县| 行唐县| 衡阳县| 如东县| 德令哈市| 中江县| 侯马市| 旺苍县| 乌兰浩特市| 陆良县| 长子县| 洞口县| 洪雅县| 沂源县| 通江县| 达尔| 嘉祥县| 定日县| 兖州市| 丹棱县| 福海县| 鄄城县| 开江县| 华阴市| 葵青区|