多数据源的使用场景:

1. 为了系统性能,数据库采用了读写分离,应用写主库,读从库

2. 项目业务有不同的数据库,比如电商系统,有用户库、商品库、交易库。

pom.xml配置:(注意版本号,低于这个版本可能会启动报错。。。被坑过)

我的springBoot版本是:2.3.0.RELEASE

<dependency>
     <groupId>com.baomidou</groupId>
     <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
     <version>3.5.0</version>
</dependency>

springBoot的yml配置:

spring:
    datasource:
    druid: # Druid 【监控】相关的全局配置
      web-stat-filter:
        enabled: true
      stat-view-servlet:
        enabled: true
        allow: # 设置白名单,不填则允许所有访问
        url-pattern: /druid/*
        login-username: admin # 控制台管理用户名和密码
        login-password: 123456
      filter:
        stat:
          enabled: true
          log-slow-sql: true # 慢 SQL 记录
          slow-sql-millis: 100
          merge-sql: true
        wall:
          config:
            multi-statement-allow: true
    dynamic: # 多数据源配置
      druid: # Druid 【连接池】相关的全局配置
        initial-size: 5 # 初始连接数
        min-idle: 10 # 最小连接池数量
        max-active: 20 # 最大连接池数量
        max-wait: 600000 # 配置获取连接等待超时的时间,单位:毫秒
        time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒
        min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位:毫秒
        max-evictable-idle-time-millis: 900000 # 配置一个连接在池中最大生存的时间,单位:毫秒
        #        validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效
        test-while-idle: true
        test-on-borrow: false
        test-on-return: false
      # 设置默认的数据源或者数据源组,默认值即为master
      primary: userDb
      datasource:
        userDb:
          driver-class-name: com.mysql.jdbc.Driver
          url: jdbc:mysql://rm-1.mysql.rds.aliyuncs.com:3306/a?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
          username: aa
          password: bb
        productDb:
          driver-class-name: com.mysql.jdbc.Driver
          url: jdbc:mysql://rm-2.mysql.rds.aliyuncs.com:3306/b?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
          username: aa
          password: bb

另外,如果有自己的Druid配置类,请注释,怕有冲突。我的就有,注释这个类就好了

测试实现类A:我采用@Ds注解在service方法上面


@Transactional //本类下面的所有方法开始事务机制 
@Service(value = "userBaseInfoDynamic")
@DS("userDb")//这里用了 以下方法默认都是这个,方法也可以单独定义
public class UserBaseInfoDynamicImpl implements UserBaseInfoDynamic {

    @Autowired
    UserBaseInfoMapper userBaseInfoMapper;

    @Resource
    ShopItemInfoMapper shopItemInfoMapper;

    @Resource(name = "userBaseInfoDynamicProduct")
    UserBaseInfoDynamic userBaseInfoDynamicProduct;

    @DS("userDb")
    @Override
    public String selectNickName(long userId) {
        UserBaseInfo userBaseInfo = userBaseInfoMapper.selectByPrimaryKey(userId);
        return userBaseInfo == null ? null : userBaseInfo.getNickName();
    }

    @DS("productDb")
    @Override
    public String selectProductName(long itemId) {
        ShopItemInfo shopItemInfo = shopItemInfoMapper.selectByPrimaryKey(itemId);
        return shopItemInfo == null ? null : shopItemInfo.getItemName();
    }

    @DS("productDb")
    @Override
    public boolean updateItem(long itemId,String itemName) {
        ShopItemInfo shopItemInfo = new ShopItemInfo();
        shopItemInfo.setId(itemId);
        shopItemInfo.setItemName(itemName);
        int i = shopItemInfoMapper.updateByPrimaryKeySelective(shopItemInfo);
        return i == 1;
    }

    @DS("userDb")
    @Override
    public boolean updateItemUserDb(long itemId,String itemName) {
        ShopItemInfo shopItemInfo = new ShopItemInfo();
        shopItemInfo.setId(itemId);
        shopItemInfo.setItemName(itemName);
        int i = shopItemInfoMapper.updateByPrimaryKeySelective(shopItemInfo);
        return i == 1;
    }
    @DS("userDb")
    @Override
    public boolean updateItemAll(long itemId,String itemName){
        //以下要单独调用另外一个bean的方法,调用自己的没用,因为单个service的方法不支持垮数据源
        System.out.println(userBaseInfoDynamicProduct.updateItem(itemId,itemName));
        System.out.println(updateItemUserDb(itemId,itemName));
        //int i = 1/0;
        return true;
    }

以上关键核心点:

userBaseInfoDynamicProduct.updateItem需要搞一个另外service封装调用,调用自己updateItem方法的没用,哪怕指定另外一个数据源,因为单个service方法里面不能垮数据源,只能通过另外的bean调用

测试实现类B:


@Transactional //本类下面的所有方法开始事务机制
@Service(value = "userBaseInfoDynamicProduct")
@DS("productDb")
public class UserBaseInfoDynamicImplProduct implements UserBaseInfoDynamic {

    @Autowired
    UserBaseInfoMapper userBaseInfoMapper;

    @Resource
    ShopItemInfoMapper shopItemInfoMapper;

    @DS("productDb")
    @Override
    public String selectNickName(long userId) {
        UserBaseInfo userBaseInfo = userBaseInfoMapper.selectByPrimaryKey(userId);
        return userBaseInfo == null ? null : userBaseInfo.getNickName();
    }

    @DS("productDb")
    @Override
    public String selectProductName(long itemId) {
        ShopItemInfo shopItemInfo = shopItemInfoMapper.selectByPrimaryKey(itemId);
        return shopItemInfo == null ? null : shopItemInfo.getItemName();
    }

    @DS("productDb")
    @Override
    public boolean updateItem(long itemId,String itemName) {
        ShopItemInfo shopItemInfo = new ShopItemInfo();
        shopItemInfo.setId(itemId);
        shopItemInfo.setItemName(itemName);
        int i = shopItemInfoMapper.updateByPrimaryKeySelective(shopItemInfo);
        return i == 1;
    }

    @Override
    public boolean updateItemUserDb(long itemId, String itemName) {
        return false;
    }

    @Override
    public boolean updateItemAll(long itemId, String itemName) {
        return false;
    }

}

接口:


public interface UserBaseInfoDynamic {
    String selectNickName(long userId);

    String selectProductName(long itemId);



    boolean updateItem(long itemId,String itemName);

    boolean updateItemUserDb(long itemId,String itemName);

    boolean updateItemAll(long itemId,String itemName);

}

单元测试:


@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = CarownerhomeWxMiniprogramApplication.class)
public class UserBaseInfoServiceDynamicTest {
    @Resource(name = "userBaseInfoDynamic")
    UserBaseInfoDynamic userBaseInfoDynamic;

    @Resource(name = "userBaseInfoDynamicProduct")
    UserBaseInfoDynamic userBaseInfoDynamicProduct;

    @Resource
    BusinessTypeInfoService businessTypeInfoService;
    @Test
    public void testDynamic() {
        String nickName = userBaseInfoDynamic.selectNickName(10001);
        System.out.println("从user库获取的昵称:"+nickName);
        String productName = userBaseInfoDynamic.selectProductName(1028);
        System.out.println("从user库获取的商品名称:"+productName);


        String nickName2 = userBaseInfoDynamicProduct.selectNickName(10001);
        System.out.println("从product库获取的昵称:"+nickName2);
        String productName2 = userBaseInfoDynamicProduct.selectProductName(1028);
        System.out.println("从product库获取的商品名称:"+productName2);


        List<BusinessTypeInfo> businessTypeInfos = businessTypeInfoService.selectList(1001l);
        System.out.println("商家类型:"+businessTypeInfos.get(0).getBusinessTypeName());


        userBaseInfoDynamic.updateItemAll(1028,"测试多数据源事务商品");
    }

}
DSTransactional使用场景:如果一个service方法里面调用两个不同mapper的数据源(@DS在mapper类上面)
   
   /**这里如果用@Transactional,
   那么slaveMapper还是访问的masterMapper初次的数据源
   **/
    @DSTransactional 
    public void Add(){
        User user = new User();
        user.setUsername("张三");
        user.setPassword("123456");
        masterMapper.insertUser(user);
        Role role = new Role();
        role.setRole("管理员");
        slaveMapper.insertRole(role);
        }
@Mapper
@DS("master")
public interface MasterMapper {
    int insertUser(User user);
}
@Mapper
@DS("slave")
public interface SlaveMapper {
    int insertRole(Role role);
}

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐