java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > springboot dynamic多数据源demo及常见切换、事务

springboot dynamic多数据源demo以及常见切换、事务的问题

作者:一片星空~

这篇文章主要介绍了springboot dynamic多数据源demo以及常见切换、事务的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

一:引入依赖

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

二:配置多数据源

yaml配置

通过yaml配置主数据源,这里就只配置了一个主数据源,后续通过代码来自由的切换数据源。

spring:
  datasource:
    dynamic:
      hikari:
        connection-timeout: 5000
        idle-timeout: 30000 # 经过idle-timeout时间如果连接还处于空闲状态, 该连接会被回收
        min-idle: 5 # 池中维护的最小空闲连接数, 默认为 10 个
        max-pool-size: 16 # 池中最大连接数, 包括闲置和使用中的连接, 默认为 10 个
        max-lifetime: 60000 # 如果一个连接超过了时长,且没有被使用, 连接会被回收
        is-auto-commit: true
      primary: master #设置默认的数据源或者数据源组,默认值即为master
      strict: true #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
      datasource:
        master: # 数据源名称
          url: 
          username: 
          password: 
          driver-class-name: com.mysql.cj.jdbc.Driver
# 如下,如果你是确定的几个数据源,可以直接都在yaml配置写死即可
#        slave_1:
#          url: 
#          username: 
#          password: 
#          driver-class-name: com.mysql.cj.jdbc.Driver
其中数据库连接池,所有的数据库统一配置,也可以单独配置,例如:
datasource:
        master: # 数据源名称
          url: 
          username: 
          password: 
          driver-class-name: com.mysql.cj.jdbc.Driver
          hikari:
            connection-timeout: 5000
            idle-timeout: 30000 # 经过idle-timeout时间如果连接还处于空闲状态, 该连接会被回收
            min-idle: 5 # 池中维护的最小空闲连接数, 默认为 10 个
            max-pool-size: 16 # 池中最大连接数, 包括闲置和使用中的连接, 默认为 10 个
            max-lifetime: 60000 # 如果一个连接超过了时长,且没有被使用, 连接会被回收
            is-auto-commit: true

三:切换数据源DS注解

DS放在哪里合适?

首先开发者要了解的基础知识是,DS注解是基于AOP的原理实现的,aop的常见失效场景应清楚。

比如内部调用失效,shiro代理失效。

具体见切换数据源:

示例:

@Service
@DS("common")
public class BookService extends ServiceImpl<BookMapper, Book> {
    @Resource
    private BookMapper bookMapper;
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void save(ReqDto reqDto) {
        bookMapper.save(reqDto);
    }
}
 

等。

四:切换数据源以及事务相关问题

1.使用动态数据源(@DS)时

@Transactional使用不当会照成@DS失效。

解决方法:

2.@Transaction开启了事务

为什么多数据源事务不生效?

@Transaction开启了事务,为什么多数据源事务不生效? 简单来说:嵌套数据源的service中,如果操作了多个数据源,不能在最外层加上@Transaction开启事务,否则切换数据源不生效,因为这属于分布式事务了,需要用seata方案解决,如果是单个数据源(不需要切换数据源)可以用@Transaction开启事务,保证每个数据源自己的完整性

加事务不生效的原因:dynamic-datasource切换数据源的原理就是实现了DataSource接口,实现了getConnection方法,只要在service中开启事务,service中对其他数据源操作只会使用开启事务的数据源,因为开启事务数据源会被缓存下来,可以在DataSourceTransactionManager的doBegin方法中看见那个txObject,如果在一个事务内,就会复用Connection,所以切换不了数据源

解决方法:本地事务

通过本地事务实现很简单,就是循环提交,发生错误,循环回滚。 我们默认的前提是数据库本身不会异常,比如宕机。如数据在回滚的过程突然宕机,本地事务就会有问题。如果你需要完整分布式方案请使用seata方案。

使用方法

在最外层的方法添加 @DSTransactional,底下调用的各个类就正常切换数据源即可。

简单举例如下:

 
@DeleteMapping
//只要@DSTransactional注解下任一环节发生异常,则全局多数据源事务回滚。
@DSTransactional()
@ApiOperation("删除数据源")
public String remove(String poolName) {
    DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
    ds.removeDataSource(poolName);
    return "删除成功";
}
但一定要注意Spring事务@Transational和本地事务@DSTransactional,不能混用
 

3.其余问题了解

一:涉及需要切换数据源时

1.不能使用事务,否则数据源不会切换,使用的还是是第一次加载的数据源 。

删除 操作多数据源的方法或者类、接口 上的 注解 @Transactional() 即可。

2.第一次加载的数据源之后,第二次(第三次...)操作其它数据源,如果数据源不存在,使用的还是第一次加载的数据源

3.数据源名称最好不要包含下滑线,下滑线的数据源切换不了 

二:其他    

1.接口中A、B两个方法,A无@Transactional标签,B有,上层通过A间接调用B,此时事务不生效。     

2.接口中异常(运行时异常)被捕获而没有被抛出。默认配置下,spring 只有在抛出的异常为运行时 unchecked 异常时才回滚该事务,也就是抛出的异常为RuntimeException 的子类(Errors也会导致事务回滚),而抛出 checked 异常则不会导致事务回滚 。可通过 @Transactional rollbackFor进行配置。 

3.多线程下事务管理因为线程不属于 spring 托管,故线程不能够默认使用 spring 的事务,也不能获取spring 注入的 bean 。在被 spring 声明式事务管理的方法内开启多线程,多线程内的方法不被事务控制。一个使用了@Transactional 的方法,如果方法内包含多线程的使用,方法内部出现异常,不会回滚线程中调用方法的事务。

引用:

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文