Java多线程事务问题 有没有大佬有好的方案

有一个业务需要同时,插入三个表,这三个表分别是三个数据源,然后开三个线程同时去插入,如果有一个失败就回滚全部,否则全部提交。

...全文
379 12 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复 1

我又回来了!
处理多个数据库并保持事务一致性是分布式事务管理的常见问题。在你描述的场景中,有三个独立的数据源,假设它们彼此之间不支持分布式事务协调(例如 XA 事务),你了解到这是一个复杂的场景,因为需要确保所有操作要么全部成功要么全部失败。

以下是基本概念,以及如何执行这类操作的一些思路:

方案一:分布式事务管理器

如果你工作在支持分布式事务协议的环境中,例如使用 Java 平台,可以采用 JTA(Java Transaction API)和 JTS(Java Transaction Service),通过 XA 协议确保跨多个资源的事务一致性。这通常需要数据库和 JDBC 驱动支持 XA 接口。

方案二:两阶段提交协议

两阶段提交(2PC)是一种原子性协议,用于保证分布式系统中的事务提交与回滚的一致性。首先执行准备(prepare)阶段,所有参与者都准备好提交,并确认它们可执行操作;在提交(commit)阶段,如果所有参与者都准备好,就进行实际的提交,否则进行回滚。不过这需要数据库或应用服务器本身支持此机制。

方案三:最终一致性方案

这方案跟以上的严格 ACID 事务不同,更倾向于 BASE(基本可用、软状态、最终一致性)。常见的做法是引入消息队列和补偿事务:

  1. 使用消息队列(如 RabbitMQ、Kafka 等)来处理任务。
  2. 提交事务至各个数据库前,首先将相关操作发送至消息队列。
  3. 各个线程从消息队列领取任务,在自己的事务环境中执行数据库操作。
  4. 如某个数据库操作失败,发布一条补偿事务至队列,要求已执行成功的其他事务执行回滚。
  5. 实现自定义逻辑来保证当收到补偿请求时各个数据库执行回滚操作。

方案四:业务层面控制

  1. 在主线程中创建三个线程,每个分别负责一个数据库的操作。
  2. 将所有的插入操作封装成可逆的业务逻辑,例如记录所有操作的日志。
  3. 如果所有线程均成功,那么提交所有操作。
  4. 如果任一线程失败,主线程会通知所有其他已经成功的线程进行回滚操作,利用之前记录的日志进行业务的逆操作。

注意:

  • 分布式事务比普通事务要复杂,且开销更大,可能引入新的性能和复杂性问题。
  • 确保所有数据库都支持你选择的事务管理方式。
  • 对于分布式系统,很多情况下需要根据具体场景设计更具容错性和伸缩性的服务,允许某程度的最终一致性。

最佳做法是依照你具体的技术栈和业务需求选择最适合的方案。如果可能的话,建议重构数据结构和业务流程,尽量规避跨多个数据源的复杂事务,以简化系统设计和提升系统的稳定性与效率。

  • 举报
回复
@百锦再@新空间 这个我看了阿里的分布式事务seata支持自定义切面可以处理这个
  • 打赏
  • 举报
回复

1配置每个数据源的事务管理器: 针对每个数据源配置相应的事务管理器。
2编写业务逻辑代码: 在代码中使用 @Transactional 注解标记事务的边界。

  • 举报
回复
@大道无形我有型11 声明式事务Spring是通过动态代理来实现的,开了线程之后还能被代理到吗?
原子星 2023-12-25
  • 打赏
  • 举报
回复

如果不用现成的分布式事务,提供一个简单的思路:

  • 数据库连接在线程外部创建,事务也在线程外部管理,在线程开始前就setAutoCommit(false),不要在线程执行过程中操作事务
  • 给线程增加一个need_rollback标志,当线程执行过程中有异常,需要回滚时,设置need_rollback为true
  • 当所有线程都执行完后,检查每个线程的need_rollback标志,只要有一个为true就回滚全部,否则就提交全部

也可以从全局管理DBConnection并接管它的事务处理模式,可以做得更透明一些。

  • 举报
回复
@原子星 我自己写的一个就是差不多你说的这个思路、但是我怕我这种会死锁 我也看了阿里的分布式事务seata 他们的开发者说好像支持 有给用户自定义的切面。需要研究一下
  • 举报
回复
@什么样的生活是完美生活 没办法上传图片没办法给你们看我写的这个demo
  • 举报
回复
@原子星 我在我的文章里面发了一个demo的图片大佬帮忙看下
柠木-.- 2023-12-25
  • 打赏
  • 举报
回复

是等待三个线程都执行完成后才继续往下走吗, 可以在调用线程前开启数据库事务,然后等线程执行完成后做判断,报错或失败直接数据库回滚就行了

  • 举报
回复
@柠木-.- 我本来想的不是全部走完,自己试了之后只能等待后才能实现。
  • 打赏
  • 举报
回复

这个应该属于分布式数据库事务范畴。Java不知道。 C#的话Sqlsugar有解决办法 。

  • 举报
回复
@百锦再@新空间 哎可惜 我自己实现了一种方式 感觉不太好

291,348

社区成员

发帖
与我相关
我的任务
社区描述
一个有温度的 Java 爱好者社区,区长是 CSDN 头牌沉默王二,30万+读者,博客访问量 1000万+,全网屈指可数的博主~
社区管理员
  • 沉默王二
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧