我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Spring Boot多数据源处理事务实例分析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Spring Boot多数据源处理事务实例分析

这篇“Spring Boot多数据源处理事务实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Spring Boot多数据源处理事务实例分析”文章吧。

1. 思路梳理

首先我们来梳理一下思路。

在上篇文章中,我们是一个微服务,在 A 中分别去调用 B 和 C,当 B 或者 C 有一个执行失败的时候,就去回滚。B 和 C 都是调用远程的服务,所谓的回滚也不是传统意义上的数据库回滚,而是一种“反向补偿”,即利用一条更新 SQL,将已经更新的数据复原。在这个例子中,B 和 C 都是远程服务,操作的也都是不同的数据库,这不就是我们多数据源中的情况么!

在微服务中,一个服务实际上就代表了一个数据源,而在我们多数据源的案例中,一个注解就能标记出来一个数据源,这样一类比,你就会发现利用分布式事务来解决多数据源中的事务问题其实是非常 Easy 的。而且这里还不是微服务项目,只是一个单体项目,更简单!

不过也有一些需要注意的细节。

2. 代码实践

接下来我们就结合代码来讲讲。

2.1 案例准备

首先多数据源的案例我就不重复写了

2.2 开始整活

因为上篇文章我主要是和大家分享的 seata 的 AT 模式,所以本文也是一样,就先采用 AT 模式。

小伙伴们知道,在我们的多数据源案例中,我们用到了两个库,test08 和 test09,现在也还是这两个库,但是现在由于我们使用的是 AT 模式,我们需要在这两个库中分别创建 undo log 表,用来记录我们对表的更新操作,当事务提交之后,undo log 表中的数据就会被清除,undo log,undo log 表的脚本如下:

CREATE TABLE `undo_log` (  `id` bigint(20) NOT NULL AUTO_INCREMENT,  `branch_id` bigint(20) NOT NULL,  `xid` varchar(100) NOT NULL,  `context` varchar(128) NOT NULL,  `rollback_info` longblob NOT NULL,  `log_status` int(11) NOT NULL,  `log_created` datetime NOT NULL,  `log_modified` datetime NOT NULL,  PRIMARY KEY (`id`),  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

数据库准备好之后,接下来就是准备依赖了,seata 有两个依赖,一个是 seata-all,还有一个微服务版的,咱们这里就直接使用上篇文章中所用到的微服务版的,依赖如下:

<dependency>    <groupId>com.alibaba.cloud</groupId>    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>    <version>2.2.2.RELEASE</version></dependency>

配好之后,接下来提供两个配置文件 file.conf 和 regsigry.conf,这两个配置文件和上篇文章中介绍到的一模一样,这里不再赘述。

接下来配置 application.yaml,如下:

spring:  cloud:    alibaba:      seata:        tx-service-group: my_test_tx_group  main:    allow-circular-references: trueseata:  enable-auto-data-source-proxy: false  application-id: dd

大家看下这里的几个配置:

  • tx-service-group:这个是事务群组的名称,相关名字是在 file.conf 中配置的。

  • allow-circular-references:这个是允许循环依赖,可能有的小伙伴已经知道,现在最新版的 Spring Boot 中已经禁掉了循环依赖,但是这个 seata 中似乎还是用到了循环依赖,所以要开启。

  • enable-auto-data-source-proxy:由于 seata 会自动代理数据源,但是我们现在的数据源是自己加载的,所以关闭掉这个数据源的自动代理,将来用自己的。

  • application-id:给我们的应用取一个名字。

好啦,这个文件就配置好了。

接下来就是数据源问题了,刚刚说了,seata 中会自动代理数据源,用到的代理对象是 DataSourceProxy,而我们在之前自定义的数据源加载中,并没有用到这个 DataSourceProxy 对象所以这里要稍作修改,一共改两个地方,如下:

LoadDataSource.java

@Component@EnableConfigurationProperties(DruidProperties.class)public class LoadDataSource {    @Autowired    DruidProperties druidProperties;    public Map<String, DataSourceProxy> loadAllDataSource() {        Map<String, DataSourceProxy> map = new HashMap<>();        Map<String, Map<String, String>> ds = druidProperties.getDs();        try {            Set<String> keySet = ds.keySet();            for (String key : keySet) {                DataSource dataSource = druidProperties.dataSource((DruidDataSource) DruidDataSourceFactory.createDataSource(ds.get(key)));                DataSourceProxy proxyDs = new DataSourceProxy(dataSource);                map.put(key, proxyDs);            }        } catch (Exception e) {            e.printStackTrace();        }        return map;    }}

其实这里的改动就是把之前的 DataSource 用 DataSourceProxy 重新包裹一下,然后将获取到的 DataSourceProxy 存起来。最后再修改一下动态数据源的地方:

@Componentpublic class DynamicDataSource extends AbstractRoutingDataSource {    public DynamicDataSource(LoadDataSource loadDataSource) {        //1.设置所有的数据源        Map<String, DataSourceProxy> allDs = loadDataSource.loadAllDataSource();        super.setTargetDataSources(new HashMap<>(allDs));        //2.设置默认的数据源        //将来,并不是所有的方法上都有 @DataSource 注解,对于那些没有 @DataSource 注解的方法,该使用哪个数据源?        super.setDefaultTargetDataSource(allDs.get(DataSourceType.DEFAULT_DS_NAME));        //3        super.afterPropertiesSet();    }        @Override    protected Object determineCurrentLookupKey() {        return DynamicDataSourceContextHolder.getDataSourceType();    }}

Map 中的 value 类型变为 DataSourceProxy,其他都不变。

另外还有一个地方要改造下,就是解析 @DataSource 注解的切面,在之前的解析中,我们是将异常捕获了,现在我们要将之抛出来,如下:

@Around("pc()")public Object around(ProceedingJoinPoint pjp) throws Throwable {    //获取方法上面的有效注解    DataSource dataSource = getDataSource(pjp);    if (dataSource != null) {        //获取注解中数据源的名称        String value = dataSource.value();        DynamicDataSourceContextHolder.setDataSourceType(value);    }    try {        return pjp.proceed();    } finally {        DynamicDataSourceContextHolder.clearDataSourceType();    }}

将之抛出来的原因也很简单,因为这是切面方法,所有的 service 层方法都在这里执行,如果将异常捕获了,将来 service 层方法不抛出异常,事务就没法生效了。

好了,现在准备工作就算是到位了。

接下来我们写一个简单的多数据源事务的案例,首先我们来创建一个 MasterService,专门用来操作 master 数据源:

@Servicepublic class MasterService {    @Autowired    MasterMapper masterMapper;    @DataSource("master")    public void addUser(String username, Integer age) {        masterMapper.addUser(username, age);    }}

mapper 就不用看了吧,就是普通的添加,大家可以在文末下载本文案例案例。

再来一个 SlaveService,用来操作 slave 数据源:

@Servicepublic class SlaveService {    @Autowired    SlaveMapper slaveMapper;    @DataSource("slave")    public void addAccount(String name, Double balance) {        int i = 1 / 0;        slaveMapper.addAccount(name, balance);    }}

slave 数据源的方法中有一个异常。

最后,我们在 UserService 中分别调用这两个方法:

@Servicepublic class UserService {    @Autowired    MasterService masterService;    @Autowired    SlaveService slaveService;    @GlobalTransactional(rollbackFor = Exception.class)    public void test() {        masterService.addUser("javaboy.org", 99);        slaveService.addAccount("javaboy.org", 99.0);    }}

注意,test 方法上有一个全局事务注解。

好啦,齐活!现在我们去执行这个 test 方法,由于 slaveService#addAccount 中的方法会抛出异常,所以会导致整个事务回滚,最终的结果就是 master 中也没有添加进数据。

以上就是关于“Spring Boot多数据源处理事务实例分析”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注编程网行业资讯频道。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Spring Boot多数据源处理事务实例分析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Spring Boot多数据源处理事务实例分析

这篇“Spring Boot多数据源处理事务实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Spring Boot多数
2023-06-30

Spring Boot多数据源及其事务管理配置方法

准备工作先给我们的项目添加Spring-JDBC依赖和需要访问数据库的驱动依赖。配置文件spring.datasource.prod.driverClassName=com.mysql.jdbc.Driverspring.datasourc
2023-05-31

Spring Boot数据响应问题实例分析

本文小编为大家详细介绍“Spring Boot数据响应问题实例分析”,内容详细,步骤清晰,细节处理妥当,希望这篇“Spring Boot数据响应问题实例分析”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。前言响应页
2023-06-29

JPA多数据源分布式事务的示例分析

这篇文章主要介绍了JPA多数据源分布式事务的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。问题背景在解决mysql字段脱敏处理时,结合sharding-jdbc的脱敏
2023-06-29

python数据处理实例分析

今天小编给大家分享一下python数据处理实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一,前言我们现在拿到了一个十
2023-06-30

Spring boot jpa 删除数据和事务管理的问题实例详解

今天我们介绍的是jpa删除和事务的一些坑,接下来看看具体内容。业务场景(这是一个在线考试系统)和代码:根据问题的id删除答案repository层:int deleteByQuestionId(Integer questionId);
2023-05-31

详解基于spring多数据源动态调用及其事务处理

需求:有些时候,我们需要连接多个数据库,但是,在方法调用前并不知道到底是调用哪个。即同时保持多个数据库的连接,在方法中根据传入的参数来确定。下图的单数据源的调用和多数据源动态调用的流程,可以看出在Dao层中需要有一个DataSource选择
2023-05-31

Pandas数据分析多文件批次聚合处理实例解析

这篇文章主要为大家介绍了Pandas数据分析多文件批次聚合处理实例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-02-15

Spring数据库连接池实现原理实例分析

这篇“Spring数据库连接池实现原理实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Spring数据库连接池实现原理
2023-07-04

springboot-jta-atomikos多数据源事务管理如何实现

这篇文章主要介绍“springboot-jta-atomikos多数据源事务管理如何实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“springboot-jta-atomikos多数据源事务管理如
2023-06-29

springboot+mybatisplus+druid如何实现多数据源+分布式事务

这篇文章主要介绍springboot+mybatisplus+druid如何实现多数据源+分布式事务,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!  jdk环境:1.8  springboot:2.1.3.RELEA
2023-06-02

Python Pandas数据处理高频操作实例分析

这篇文章主要介绍“Python Pandas数据处理高频操作实例分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Python Pandas数据处理高频操作实例分析”文章能帮助大家解决问题。引入依赖
2023-07-02

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录