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

Spring Boot 集成Mybatis實(shí)現(xiàn)主從(多數(shù)據(jù)源)分離方案示例

 更新時(shí)間:2017年03月07日 14:10:37   作者:險(xiǎn)遠(yuǎn)的奇?zhèn)ピ幑? 
本篇文章主要介紹了Spring Boot 集成Mybatis實(shí)現(xiàn)主從(多數(shù)據(jù)源)分離方案實(shí)例,具有一定的參考價(jià)值,有興趣的可以了解一下。

本文將介紹使用Spring Boot集成Mybatis并實(shí)現(xiàn)主從庫(kù)分離的實(shí)現(xiàn)(同樣適用于多數(shù)據(jù)源)。延續(xù)之前的Spring Boot 集成MyBatis。項(xiàng)目還將集成分頁(yè)插件PageHelper、通用Mapper以及Druid。

新建一個(gè)Maven項(xiàng)目,最終項(xiàng)目結(jié)構(gòu)如下:

多數(shù)據(jù)源注入到sqlSessionFactory

POM增加如下依賴(lài):

<!--JSON-->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.datatype</groupId>
      <artifactId>jackson-datatype-joda</artifactId>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.module</groupId>
      <artifactId>jackson-module-parameter-names</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.0.11</version>
    </dependency>
    <!--mybatis-->
    <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>1.1.1</version>
    </dependency>
    <!--mapper-->
    <dependency>
      <groupId>tk.mybatis</groupId>
      <artifactId>mapper-spring-boot-starter</artifactId>
      <version>1.1.0</version>
    </dependency>
    <!--pagehelper-->
    <dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper-spring-boot-starter</artifactId>
      <version>1.1.0</version>
      <exclusions>
        <exclusion>
          <artifactId>mybatis-spring-boot-starter</artifactId>
          <groupId>org.mybatis.spring.boot</groupId>
        </exclusion>
      </exclusions>
    </dependency>

這里需要注意的是:項(xiàng)目是通過(guò)擴(kuò)展mybatis-spring-boot-starter的org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration來(lái)實(shí)現(xiàn)多數(shù)據(jù)源注入的。在mybatis-spring-boot-starter:1.2.0中,該類(lèi)取消了默認(rèn)構(gòu)造函數(shù),因此本項(xiàng)目依舊使用1.1.0版本。需要關(guān)注后續(xù)版本是否會(huì)重新把擴(kuò)展開(kāi)放處理。

之所以依舊使用舊方案,是我個(gè)人認(rèn)為開(kāi)放擴(kuò)展是合理的,相信在未來(lái)的版本中會(huì)回歸。

如果你需要其他方案可參考傳送門(mén)

增加主從庫(kù)配置(application.yml)

druid:
  type: com.alibaba.druid.pool.DruidDataSource
  master:
    url: jdbc:mysql://192.168.249.128:3307/db-test?characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useUnicode=true
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: root
    initial-size: 5
    min-idle: 1
    max-active: 100
    test-on-borrow: true
  slave:
    url: jdbc:mysql://192.168.249.128:3317/db-test?characterEncoding=UTF-8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.jdbc.Driver
    username: root
    password: root
    initial-size: 5
    min-idle: 1
    max-active: 100
    test-on-borrow: true

創(chuàng)建數(shù)據(jù)源

@Configuration
@EnableTransactionManagement
public class DataSourceConfiguration {

  @Value("${druid.type}")
  private Class<? extends DataSource> dataSourceType;

  @Bean(name = "masterDataSource")
  @Primary
  @ConfigurationProperties(prefix = "druid.master")
  public DataSource masterDataSource(){
    return DataSourceBuilder.create().type(dataSourceType).build();
  }

  @Bean(name = "slaveDataSource")
  @ConfigurationProperties(prefix = "druid.slave")
  public DataSource slaveDataSource1(){
    return DataSourceBuilder.create().type(dataSourceType).build();
  }
}

將多數(shù)據(jù)源注入到sqlSessionFactory中

前面提到了這里通過(guò)擴(kuò)展mybatis-spring-boot-starter的org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration來(lái)實(shí)現(xiàn)多數(shù)據(jù)源注入的

@Configuration
@AutoConfigureAfter({DataSourceConfiguration.class})
public class MybatisConfiguration extends MybatisAutoConfiguration {

  private static Log logger = LogFactory.getLog(MybatisConfiguration.class);

  @Resource(name = "masterDataSource")
  private DataSource masterDataSource;
  @Resource(name = "slaveDataSource")
  private DataSource slaveDataSource;

  @Bean
  public SqlSessionFactory sqlSessionFactory() throws Exception {
    return super.sqlSessionFactory(roundRobinDataSouceProxy());
  }

  public AbstractRoutingDataSource roundRobinDataSouceProxy(){
    ReadWriteSplitRoutingDataSource proxy = new ReadWriteSplitRoutingDataSource();
    Map<Object,Object> targetDataResources = new ClassLoaderRepository.SoftHashMap();
    targetDataResources.put(DbContextHolder.DbType.MASTER,masterDataSource);
    targetDataResources.put(DbContextHolder.DbType.SLAVE,slaveDataSource);
    proxy.setDefaultTargetDataSource(masterDataSource);//默認(rèn)源
    proxy.setTargetDataSources(targetDataResources);
    return proxy;
  }
}

實(shí)現(xiàn)讀寫(xiě)分離(多數(shù)據(jù)源分離)

這里主要思路如下:

1-將不同的數(shù)據(jù)源標(biāo)識(shí)記錄在ThreadLocal中

2-通過(guò)注解標(biāo)識(shí)出當(dāng)前的service方法使用哪個(gè)庫(kù)

3-通過(guò)Spring AOP實(shí)現(xiàn)攔截注解并注入不同的標(biāo)識(shí)到threadlocal中

4-獲取源的時(shí)候通過(guò)threadlocal中不同的標(biāo)識(shí)給出不同的sqlSession

標(biāo)識(shí)存放ThreadLocal的實(shí)現(xiàn)

public class DbContextHolder {

  public enum DbType{
    MASTER,SLAVE
  }

  private static final ThreadLocal<DbType> contextHolder = new ThreadLocal<>();

  public static void setDbType(DbType dbType){
    if(dbType==null)throw new NullPointerException();
    contextHolder.set(dbType);
  }

  public static DbType getDbType(){
    return contextHolder.get()==null?DbType.MASTER:contextHolder.get();
  }

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

}

注解實(shí)現(xiàn)

/**
 * 該注解注釋在service方法上,標(biāo)注為鏈接slaves庫(kù)
 * Created by Jason on 2017/3/6.
 */
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ReadOnlyConnection {
}

Spring AOP對(duì)注解的攔截

@Aspect
@Component
public class ReadOnlyConnectionInterceptor implements Ordered {

  public static final Logger logger = LoggerFactory.getLogger(ReadOnlyConnectionInterceptor.class);

  @Around("@annotation(readOnlyConnection)")
  public Object proceed(ProceedingJoinPoint proceedingJoinPoint,ReadOnlyConnection readOnlyConnection) throws Throwable {
    try {
      logger.info("set database connection to read only");
      DbContextHolder.setDbType(DbContextHolder.DbType.SLAVE);
      Object result = proceedingJoinPoint.proceed();
      return result;
    }finally {
      DbContextHolder.clearDbType();
      logger.info("restore database connection");
    }
  }


  @Override
  public int getOrder() {
    return 0;
  }
}

根據(jù)標(biāo)識(shí)獲取不同源

這里我們通過(guò)擴(kuò)展AbstractRoutingDataSource來(lái)獲取不同的源。它是Spring提供的一個(gè)可以根據(jù)用戶(hù)發(fā)起的不同請(qǐng)求去轉(zhuǎn)換不同的數(shù)據(jù)源,比如根據(jù)用戶(hù)的不同地區(qū)語(yǔ)言選擇不同的數(shù)據(jù)庫(kù)。通過(guò)查看源碼可以發(fā)現(xiàn),它是通過(guò)determineCurrentLookupKey()返回的不同key到sqlSessionFactory中獲取不同源(前面已經(jīng)展示了如何在sqlSessionFactory中注入多個(gè)源)

public class ReadWriteSplitRoutingDataSource extends AbstractRoutingDataSource {

  @Override
  protected Object determineCurrentLookupKey() {
    return DbContextHolder.getDbType();
  }
}

以上就完成了讀寫(xiě)分離(多數(shù)據(jù)源)的配置方案。下面是一個(gè)具體的實(shí)例

使用方式

Entity

@Table(name = "t_sys_dic_type")
public class DicType extends BaseEntity{

  String code;

  String name;

  Integer status;

  ...
}

Mapper

public interface DicTypeMapper extends BaseMapper<DicType> {
}

Service

@Service
public class DicTypeService {
  @Autowired
  private DicTypeMapper dicTypeMapper;

  @ReadOnlyConnection
  public List<DicType> getAll(DicType dicType){
    if (dicType.getPage() != null && dicType.getRows() != null) {
      PageHelper.startPage(dicType.getPage(), dicType.getRows());
    }
    return dicTypeMapper.selectAll();
  }

}

注意這里的@ReadOnlyConnection注解

Controller

@RestController
@RequestMapping("/dictype")
public class DicTypeController {
  @Autowired
  private DicTypeService dicTypeService;

  @RequestMapping(value = "/all")
  public PageInfo<DicType> getALL(DicType dicType){
    List<DicType> dicTypeList = dicTypeService.getAll(dicType);
    return new PageInfo<>(dicTypeList);
  }
}

通過(guò)mvn spring-boot:run啟動(dòng)后,即可通過(guò)http://localhost:9090/dictype/all 獲取到數(shù)據(jù)

后臺(tái)打印出

c.a.d.m.ReadOnlyConnectionInterceptor  : set database connection to read only

說(shuō)明使用了從庫(kù)的鏈接獲取數(shù)據(jù)

備注:如何保證多源事務(wù)呢?

1-在讀寫(xiě)分離場(chǎng)景中不會(huì)考慮主從庫(kù)事務(wù),在純讀的上下文上使用@ReadOnlyConnection標(biāo)簽。其他則默認(rèn)使用主庫(kù)。

2-在多源場(chǎng)景中,Spring的@Transaction是可以保證多源的事務(wù)性的。

本文使用代碼

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論