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

 更新时间:2023年07月31日 10:05:08   作者:一片星空~  
这篇文章主要介绍了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代理失效。

具体见切换数据源:

  • 1.通常建议DS放在serviceImpl的方法上,如事务注解一样。(常用方式二:访问第三方库api,单独抽取接口,并作数据处理) 
  • 2.注解在Controller的方法上或类上:并不是不可以,并不建议的原因主要是controller主要作用是参数的检验等一些基础逻辑的处理,这部分操作常常并不涉及数据库 
  • 3.注解在service的实现类的方法或类上:这是建议的方式,service主要是对业务的处理, 在复杂的场景涉及连续切换不同的数据库。 如果你的方法有通用性,其他service也会调用你的方法。 这样别人就不用重复处理切换数据源 
  • 4.注解在mapper上。(常用方式一):通常如果你某个Mapper对应的表只在确定的一个库,也是可以的。 但是建议只注解在Mapper的类上。 
  • 5.其他使用方式:继承抽象类上的DS 
  • 6.继承接口上的DS

示例:

@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失效。

  • 1.实现层上面加@Transactional,数据源没有切换
  • 2.开启事务的同时,会从数据库连接池获取数据库连接;
  • 3.如果内层的service使用@DS切换数据源,只是又做了一层拦截,但是并没有改变整个事务的连接;
  • 4.在这个事务内的所有数据库操作,都是在事务连接建立之后,所以会产生数据源没有切换的问题;
  • 5.为了使@DS起作用,必须替换数据库连接,也就是改变事务的传播机智,产生新的事务,获取新的数据库连接

解决方法:

  • 去除MasterService.upload上面的@Transactional,数据源切换正常,虽然可以解决,但是事务无效。
  • BookService的save上面加@Transactional(propagation =Propagation.REQUIRES_NEW),数据源切换,且事务有效。
  • 完美解决。它会重新创建新事务,获取新的数据库连接,从而得到@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 的方法,如果方法内包含多线程的使用,方法内部出现异常,不会回滚线程中调用方法的事务。

引用:

总结

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

相关文章

  • Mybatis 逆向工程的三种方法详解

    Mybatis 逆向工程的三种方法详解

    这篇文章主要介绍了Mybatis 逆向工程的三种方法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10
  • SpringCloud 分布式锁的多种实现

    SpringCloud 分布式锁的多种实现

    本文主要介绍了SpringCloud 分布式锁的多种实现,主要有三种方式,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • SpringBoot如何配置数据库主从shardingsphere

    SpringBoot如何配置数据库主从shardingsphere

    这篇文章主要介绍了SpringBoot如何配置数据库主从shardingsphere问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-04-04
  • 使用java 实现mqtt两种常用方式

    使用java 实现mqtt两种常用方式

    在开发MQTT时有两种方式一种是使用Paho Java 原生库来完成,一种是使用spring boot 来完成,这篇文章主要介绍了使用java 实现mqtt两种方式,需要的朋友可以参考下
    2022-11-11
  • spring Cloud微服务跨域实现步骤

    spring Cloud微服务跨域实现步骤

    这篇文章主要介绍了spring Cloud微服务跨域实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • Java中SpringCloud的五大组件详解

    Java中SpringCloud的五大组件详解

    这篇文章主要介绍了Java中SpringCloud的五大组件详解,Spring cloud是一个基于Spring Boot实现的服务治理工具包,在微服务架构中用于管理和协调服务,需要的朋友可以参考下
    2023-07-07
  • Java web网站访问量的统计

    Java web网站访问量的统计

    这篇文章主要为大家详细介绍了Java web网站访问量的统计,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-01-01
  • idea导入项目不显示maven侧边栏的问题及解决方法

    idea导入项目不显示maven侧边栏的问题及解决方法

    这篇文章主要介绍了idea导入项目不显示maven侧边栏的问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-07-07
  • Mybatis执行多条语句/批量更新方式

    Mybatis执行多条语句/批量更新方式

    这篇文章主要介绍了Mybatis执行多条语句/批量更新方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • 使用Netty搭建服务端和客户端过程详解

    使用Netty搭建服务端和客户端过程详解

    这篇文章主要介绍了使用Netty搭建服务端和客户端过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-07-07

最新评论