全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

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

本文将介绍使用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是可以保证多源的事务性的。

本文使用代码

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


# spring  # boot  # 多数据源  # spring主从数据源  # 主从  # MyBatis-Plus+Druid配置及应用详解  # MyBatis-Plus集成Druid环境搭建的详细教程  # springboot-mongodb的多数据源配置的方法步骤  # 详解Spring Boot整合Mybatis实现 Druid多数据源配置  # Spring Boot 动态数据源示例(多数据源自动切换)  # Springboot mybatis plus druid多数据源解决方案 dynamic-data  # 它是  # 来实现  # 的是  # 是一个  # 如果你  # 景中  # 多个  # 适用于  # 还将  # 分页  # 可以根据  # 是否会  # 需要注意  # 中会  # 大家多多  # 新建一个  # 离场  # 完成了  # 传送门  # 使用了 


相关文章: 如何快速生成橙子建站落地页链接?  javascript基本数据类型及类型检测常用方法小结  天河区网站制作公司,广州天河区如何办理身份证?需要什么资料有预约的网站吗?  外贸公司网站制作哪家好,maersk船公司官网?  如何确保FTP站点访问权限与数据传输安全?  定制建站平台哪家好?企业官网搭建与快速建站方案推荐  制作网站建设的公司有哪些,网站建设比较好的公司都有哪些?  活动邀请函制作网站有哪些,活动邀请函文案?  山东云建站价格为何差异显著?  怎么将XML数据可视化 D3.js加载XML  如何在新浪SAE免费搭建个人博客?  湖北网站制作公司有哪些,湖北清能集团官网?  如何在自有机房高效搭建专业网站?  5种Android数据存储方式汇总  道歉网站制作流程,世纪佳缘致歉小吴事件,相亲网站身份信息伪造该如何稽查?  如何在阿里云虚拟机上搭建网站?步骤解析与避坑指南  制作网站的软件下载免费,今日头条开宝箱老是需要下载怎么回事?  建站VPS选购需注意哪些关键参数?  如何正确下载安装西数主机建站助手?  如何通过西部建站助手安装IIS服务器?  如何在阿里云部署织梦网站?  太平洋网站制作公司,网络用语太平洋是什么意思?  如何通过IIS搭建网站并配置访问权限?  Swift中swift中的switch 语句  利用JavaScript实现拖拽改变元素大小  高端企业智能建站程序:SEO优化与响应式模板定制开发  如何在Golang中使用encoding/gob序列化对象_存储和传输数据  如何处理“XML格式不正确”错误 常见XML well-formed问题解决方法  建站主机是否等同于虚拟主机?  如何通过建站之星自助学习解决操作问题?  如何高效生成建站之星成品网站源码?  重庆市网站制作公司,重庆招聘网站哪个好?  seo网站制作优化,网站SEO优化步骤有哪些?  制作门户网站的参考文献在哪,小说网站怎么建立?  宝塔建站无法访问?如何排查配置与端口问题?  建站之星备案流程有哪些注意事项?  长春网站建设制作公司,长春的网络公司怎么样主要是能做网站的?  建站之星2.7模板快速切换与批量管理功能操作指南  深圳 网站制作,深圳招聘网站哪个比较好一点啊?  娃派WAP自助建站:免费模板+移动优化,快速打造专业网站  如何在万网自助建站平台快速创建网站?  台州网站建设制作公司,浙江手机无犯罪记录证明怎么开?  免费视频制作网站,更新又快又好的免费电影网站?  专业型网站制作公司有哪些,我设计专业的,谁给推荐几个设计师兼职类的网站?  高防服务器如何保障网站安全无虞?  如何在建站之星网店版论坛获取技术支持?  宝塔新建站点报错如何解决?  移民网站制作流程,怎么看加拿大移民官网?  建站之星价格显示格式升级,你的预算足够吗?  南平网站制作公司,2025年南平市事业单位报名时间? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。