当前位置: 移动技术网 > IT编程>开发语言>Java > Spring Boot 集成Mybatis实现主从(多数据源)分离方案示例

Spring Boot 集成Mybatis实现主从(多数据源)分离方案示例

2019年07月22日  | 移动技术网IT编程  | 我要评论

有关六一儿童节的手抄报,201315,绝对丽奴下载

本文将介绍使用spring boot集成mybatis并实现主从库分离的实现(同样适用于多数据源)。延续之前的spring boot 集成mybatis。项目还将集成分页插件pagehelper、通用mapper以及druid。

新建一个maven项目,最终项目结构如下:

多数据源注入到sqlsessionfactory

pom增加如下依赖:

<!--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>

这里需要注意的是:项目是通过扩展mybatis-spring-boot-starter的org.mybatis.spring.boot.autoconfigure.mybatisautoconfiguration来实现多数据源注入的。在mybatis-spring-boot-starter:1.2.0中,该类取消了默认构造函数,因此本项目依旧使用1.1.0版本。需要关注后续版本是否会重新把扩展开放处理。

之所以依旧使用旧方案,是我个人认为开放扩展是合理的,相信在未来的版本中会回归。

如果你需要其他方案可参考

增加主从库配置(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

创建数据源

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

将多数据源注入到sqlsessionfactory中

前面提到了这里通过扩展mybatis-spring-boot-starter的org.mybatis.spring.boot.autoconfigure.mybatisautoconfiguration来实现多数据源注入的

@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);//默认源
    proxy.settargetdatasources(targetdataresources);
    return proxy;
  }
}

实现读写分离(多数据源分离)

这里主要思路如下:

1-将不同的数据源标识记录在threadlocal中

2-通过注解标识出当前的service方法使用哪个库

3-通过spring aop实现拦截注解并注入不同的标识到threadlocal中

4-获取源的时候通过threadlocal中不同的标识给出不同的sqlsession

标识存放threadlocal的实现

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

}

注解实现

/**
 * 该注解注释在service方法上,标注为链接slaves库
 * created by jason on 2017/3/6.
 */
@target({elementtype.method,elementtype.type})
@retention(retentionpolicy.runtime)
public @interface readonlyconnection {
}

spring aop对注解的拦截

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

根据标识获取不同源

这里我们通过扩展abstractroutingdatasource来获取不同的源。它是spring提供的一个可以根据用户发起的不同请求去转换不同的数据源,比如根据用户的不同地区语言选择不同的数据库。通过查看源码可以发现,它是通过determinecurrentlookupkey()返回的不同key到sqlsessionfactory中获取不同源(前面已经展示了如何在sqlsessionfactory中注入多个源)

public class readwritesplitroutingdatasource extends abstractroutingdatasource {

  @override
  protected object determinecurrentlookupkey() {
    return dbcontextholder.getdbtype();
  }
}

以上就完成了读写分离(多数据源)的配置方案。下面是一个具体的实例

使用方式

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

通过mvn spring-boot:run启动后,即可通过http://localhost:9090/dictype/all 获取到数据

后台打印出

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

说明使用了从库的链接获取数据

备注:如何保证多源事务呢?

1-在读写分离场景中不会考虑主从库事务,在纯读的上下文上使用@readonlyconnection标签。其他则默认使用主库。

2-在多源场景中,spring的@transaction是可以保证多源的事务性的。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网