栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

springboot2.6+Mybatis注解多数据源使用dynamic-datasource-spring-boot-starter为依赖

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

springboot2.6+Mybatis注解多数据源使用dynamic-datasource-spring-boot-starter为依赖

多数据源系列

1、springboot2.6+Mybatis静态多数据源(集成JTA(Atomikos案例)实现分布式事务控制)
2、springboot2.6+Mybatis动态多数据源AOP切换(AbstractRoutingDataSource)
3、springboot2.6+Mybatis注解多数据源使用dynamic-datasource-spring-boot-starter为依赖

说明

前两篇博客介绍了用基本的方式做多数据源,可以应对一般的情况,但是遇到一些复杂的情况就需要扩展下功能了,比如:动态增减数据源、数据源分组,纯粹多库 读写分离 一主多从、从其他数据库或者配置中心读取数据源等等。其实就算没有这些需求,使用这个实现多数据源也比之前使用AbstractRoutingDataSource要便捷的多。

dynamic-datasource-spring-boot-starter 是一个基于springboot的快速集成多数据源的启动器。
github: https://github.com/baomidou/dynamic-datasource-spring-boot-starter
文档: https://github.com/baomidou/dynamic-datasource-spring-boot-starter/wiki

动态数据源方案 文件结构

maven引入:
        
            com.baomidou
            dynamic-datasource-spring-boot-starter
            3.1.0
        

        
            org.springframework.boot
            spring-boot-starter-aop
            2.3.3.RELEASE
        
通过yml配置好数据源
spring:
  datasource:
    dynamic:
      primary: master1
      strict: false
      datasource:
        master1:
          url: jdbc:mysql://127.0.0.1:3306/master1?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
          username: root
          password: andrew
          driver-class-name: com.mysql.cj.jdbc.Driver
        master2:
          url: jdbc:mysql://127.0.0.1:3306/master2?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
          username: root
          password: andrew
          driver-class-name: com.mysql.cj.jdbc.Driver
        master3:
          url: jdbc:oracle:thin:@10.132.212.63:1688:TESTDB
          username: flx
          password: flx202108
          driver-class-name: oracle.jdbc.OracleDriver

logging:
  level:
    com.xkcoding: debug
    com.xkcoding.orm.mybatis.mapper: trace

server:
  port: 8080
#  servlet:
#    context-path: /demo

mybatis:
  type-aliases-package: com.orm.mybatis.dsannotation.entity
  mapper-locations: classpath:mapper/*/*.xml
  configuration:
    map-underscore-to-camel-case: true

service层

里面在想要切换数据源的方法上加上@DS注解就行了,也可以加在整个service层上,方法上的注解优先于类上注解

@Service
public class UserServiceImpl {

    @Resource
    private UserMapper1 userMapper1;

    @Resource
    private UserMapper2 userMapper2;

    @Resource
    private AsusPoInfoMapper3 asusPoInfoMapper3;

    @DS("master1")
    public List findAllUser(){
        List list = userMapper1.selectAllUser();
        return list;
    }

    @DS("master2")
    public List findAllUser1(){
        List list = userMapper2.selectAllUser();
        return list;
    }

    public User findUserById(Long id){
        return userMapper1.selectUserById(id);
    }

    @Transactional  //与dynamic不同的是,这两个注解可以一起使用会先切换数据源再事务
    @DS("master1")  //与dynamic不同的是,这两个注解可以一起使用会先切换数据源再事务
    public void insertUser1(){
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date =  simpleDateFormat.format(new Date());
        String UUID = java.util.UUID.randomUUID().toString().substring(0,5);
        User user = User.builder().email("andrew@qq.com"+UUID).name("andrew"+UUID).password("123456"+UUID).phoneNumber("123"+UUID)
                .lastUpdateTime(date).createTime(date).status(0).salt("password"+UUID).build();
        userMapper1.saveUser(user);
    }

    @Transactional
    @DS("master2")
    public void insertUser2(){
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date =  simpleDateFormat.format(new Date());
        String UUID = java.util.UUID.randomUUID().toString().substring(0,5);
        User user = User.builder().email("andrew@qq.com"+UUID).name("andrew"+UUID).password("123456"+UUID).phoneNumber("123"+UUID)
                .lastUpdateTime(date).createTime(date).status(0).salt("password"+UUID).build();
        userMapper2.saveUser(user);
    }

    public void testTransitional() {
        ((UserServiceImpl)AopContext.currentProxy()).insertUser1();
        ((UserServiceImpl)AopContext.currentProxy()).insertUser2();
        ((UserServiceImpl)AopContext.currentProxy()).insertOracle();
    }

    @DS("master3")
    public List selectOracle(){
       return asusPoInfoMapper3.selectAllAsusPoInfo();
    }

    @DS("master3")//与dynamic不同的是,这两个注解可以一起使用会先切换数据源再事务
    @Transactional
    public void insertOracle(){
        AsusPoInfo asusPoInfo = AsusPoInfo.builder().id(java.util.UUID.randomUUID().toString().substring(0,20))
                .woNo("andrew").po("123456").poLine("poline").cPo("cpo123456").shipType("Direct").build();
        asusPoInfoMapper3.insertAsusPoInfo(asusPoInfo);
    }

}

测试多数据源回滚
package com.orm.mybatis.dsannotation;

import com.orm.mybatis.dsannotation.entity.AsusPoInfo;
import com.orm.mybatis.dsannotation.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import com.orm.mybatis.dsannotation.serviceImpl.UserServiceImpl;

import javax.annotation.Resource;
import java.util.List;

@SpringBootTest
class SpringbootMybatisDsannotationDatasourceApplicationTests {

    //事务测试
    @Resource
    private UserServiceImpl userService;

    @Test
    void contextLoads1() {
     List list = userService.selectOracle();
     System.out.println(list);
    }

    @Test
    void contextLoads2() {
        List list = userService.findAllUser();
        System.out.println(list);
    }

    @Test
    void contextLoads3() {
        List list = userService.findAllUser();
        List list1 = userService.findAllUser1();
        List list2 = userService.selectOracle();
        list.addAll(list1);
        System.out.println(list);
        System.out.println(list2);
    }

    @Test
    void contextLoads4() {
        userService.testTransitional();
    }

}


切换数据源成功,而且事务能回滚,但如果是多数据源事务,只能回滚报错的数据源的事务。

方案的权衡
    静态多数据源方案优势在于配置简单并且对业务代码的入侵性极小,缺点也显而易见:我们需要在系统中占用一些资源,而这些资源并不是一直需要,一定程度上会造成资源的浪费。如果你需要在一段业务代码中同时使用多个数据源的数据又要去考虑操作的原子性(事务)可以用spring的jta实现事务,那么这种方案无疑会适合你。(aop和dynamic)动态数据源(AbstractRoutingDataSource)方案配置上看起来配置会稍微复杂一些,但是很好的符合了“即拿即用,即用即还”的设计原则,我们把多个数据源看成了一个池子,然后进行消费。它的缺点正如上文所暴露的那样:我们往往需要在事务的需求下做出妥协。而且由于需要切换环境上下文,在高并发量的系统上进行资源竞争时容易发生死锁等活跃性问题。我们常用它来进行数据库的“读写分离”,不需要在一段业务中同时操作多个数据源。这种动态形式并不能用spring的jta实现,而且其他实现方式(seata等)虽然可以实现,但配置复杂且实用度不高。如果需要使用事务,一定记得使用分布式事务进行Spring自带事务管理的替换,否则将无法进行一致性控制。写到这里本文也就结束,好久没有撰写文章很多东西考虑不是很详尽,谢谢批评指正!
项目地址

springboot2.6+mybatis
https://gitee.com/liuweiqiang12/springboot-mybatis-dynamic-datasource

springboot2.6+mybatis-plus
https://gitee.com/liuweiqiang12/springboot-mybatis-plus-dynamic-datasource

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/785274.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号