gpt4 book ai didi

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

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:00:21 25 4
gpt4 key购买 nike

据我了解,所有事务都是线程绑定(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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com