草庐IT

java - 单事务跨多线程解决方案

coder 2024-03-04 原文

据我了解,所有事务都是线程绑定(bind)的(即上下文存储在 ThreadLocal 中)。例如如果:

  1. 我在事务父方法中启动事务
  2. 在异步调用中使数据库插入#1
  3. 让数据库在另一个异步调用中插入#2

然后这将产生两个不同的事务(每个插入一个),即使它们共享相同的“事务”父级。

例如,假设我执行了两次插入(并使用了一个非常简单的示例,即为了简洁起见,不使用执行程序或可完成的 future 等):

@Transactional
public void addInTransactionWithAnnotation() {
    addNewRow();
    addNewRow();
}

将根据需要执行两个插入,作为同一事务的一部分。

但是,如果我想并行化这些插入以提高性能:

@Transactional
public void addInTransactionWithAnnotation() {
    new Thread(this::addNewRow).start();
    new Thread(this::addNewRow).start();
}

那么每个生成的线程都不会参与事务,因为事务是线程绑定(bind)的。

关键问题:有没有办法将事务安全地传播到子线程?

我想到的解决这个问题的唯一方案:

  1. 使用 JTA 或某些 XA 管理器,根据定义应该能够做到 这个。但是,理想情况下我不想将 XA 用于我的解决方案 因为这是开销
  2. 将我想要执行的所有事务性工作(在上面的示例中,addNewRow() 函数)通过​​管道传输到单个线程,并以多线程方式完成所有先前的工作。
  3. 想办法利用 InheritableThreadLocal 处理事务状态并将其传播到子线程。我不确定该怎么做。

还有其他可能的解决方案吗?即使它有点像解决方法(如我上面的解决方案)?

最佳答案

JTA API 有几种隐式操作当前线程事务的方法,但它不会阻止您在线程之间移动或复制事务,或对未绑定(bind)到当前(或任何其他)事务的事务执行某些操作) 线。这会让人头疼不已,但这还不是最糟糕的部分......

对于原始 JDBC,您根本没有 JTA 事务。您有一个 JDBC 连接,它对事务上下文有自己的想法。在这种情况下,事务是连接绑定(bind)的,而不是线程绑定(bind)的。传递连接,tx 随之而来。但是连接不一定是线程安全的,并且无论如何都可能是性能瓶颈,因此在多个并发线程之间共享一个并不能真正帮助您。您可能需要多个认为它们在同一个事务中的连接,这意味着您需要 XA,因为这就是数据库识别此类情况的方式。这时您又回到了 JTA,但现在图片中有一个 JCA 可以正确处理连接管理。简而言之,您重新发明了 JavaEE 应用程序服务器。

对于在 JDBC 上分层的框架,例如像 Hibernate 这样的 ORM,你有一个额外的复杂性:它们的抽象不一定是线程安全的。所以你不能有一个 session 同时绑定(bind)到多个线程。但是您可以有多个并发 session ,每个 session 都参与同一个 XA 事务。

和往常一样,它归结为阿姆达尔定律。如果通过使用每个 tx 的多个连接来允许多个并发线程共享 db I/O 工作所获得的加速比从批处理中获得的加速要大,那么 XA 的开销是值得的。如果加速在本地计算中并且数据库 I/O 不是一个小问题,那么处理 JDBC 连接并将非 IO 计算工作卸载到线程池的单个线程是可行的方法。

关于java - 单事务跨多线程解决方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46968086/

有关java - 单事务跨多线程解决方案的更多相关文章

  1. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  2. ruby - 我可以使用 aws-sdk-ruby 在 AWS S3 上使用事务性文件删除/上传吗? - 2

    我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的

  3. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  4. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  5. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  6. ruby - 分布式事务和队列,ruby,erlang,scala - 2

    我有一个涉及多台机器、消息队列和事务的问题。因此,例如用户点击网页,点击将消息发送到另一台机器,该机器将付款添加到用户的帐户。每秒可能有数千次点击。事务的所有方面都应该是容错的。我以前从未遇到过这样的事情,但一些阅读表明这是一个众所周知的问题。所以我的问题。我假设安全的方法是使用两阶段提交,但协议(protocol)是阻塞的,所以我不会获得所需的性能,我是否正确?我通常写Ruby,但似乎Redis之类的数据库和Rescue、RabbitMQ等消息队列系统对我的帮助不大——即使我实现某种两阶段提交,如果Redis崩溃,数据也会丢失,因为它本质上只是内存。所有这些让我开始关注erlang和

  7. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  8. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  9. 屏幕录制为什么没声音?检查这2项,轻松解决 - 2

    相信很多人在录制视频的时候都会遇到各种各样的问题,比如录制的视频没有声音。屏幕录制为什么没声音?今天小编就和大家分享一下如何录制音画同步视频的具体操作方法。如果你有录制的视频没有声音,你可以试试这个方法。 一、检查是否打开电脑系统声音相信很多小伙伴在录制视频后会发现录制的视频没有声音,屏幕录制为什么没声音?如果当时没有打开音频录制,则录制好的视频是没有声音的。因此,建议在录制前进行检查。屏幕上没有声音,很可能是因为你的电脑系统的声音被禁止了。您只需打开电脑系统的声音,即可录制音频和图画同步视频。操作方法:步骤1:点击电脑屏幕右下侧的“小喇叭”图案,在上方的选项中,选择“声音”。 步骤2:在“声

  10. 【高数】用拉格朗日中值定理解决极限问题 - 2

    首先回顾一下拉格朗日定理的内容:函数f(x)是在闭区间[a,b]上连续、开区间(a,b)上可导的函数,那么至少存在一个,使得:通过这个表达式我们可以知道,f(x)是函数的主体,a和b可以看作是主体函数f(x)中所取的两个值。那么可以有,  也就意味着我们可以用来替换 这种替换可以用在求某些多项式差的极限中。方法: 外层函数f(x)是一致的,并且h(x)和g(x)是等价无穷小。此时,利用拉格朗日定理,将原式替换为 ,再进行求解,往往会省去复合函数求极限的很多麻烦。使用要注意:1.要先找到主体函数f(x),即外层函数必须相同。2.f(x)找到后,复合部分是等价无穷小。3.要满足作差的形式。如果是加

随机推荐