跨多线程的单事务解决方案 [英] Single transaction across multiple threads solution

查看:109
本文介绍了跨多线程的单事务解决方案的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

As I understand it, all transactions are Thread-bound (i.e. with the context stored in ThreadLocal). For example if:

  1. 我通过事务性父方法开始交易
  2. 使数据库在异步调用中插入#1
  3. 让数据库在另一个异步调用中插入#2

然后,即使它们共享相同的事务"父对象,也会产生两个不同的事务(每个插入一个).

Then that will yield two different transactions (one for each insert) even though they shared the same "transactional" parent.

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

For example, let's say I perform two inserts (and using a very simple sample, i.e. not using an executor or completable future for brevity, etc.):

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

将根据需要在同一笔交易中执行两次插入操作.

Will perform both inserts, as desired, as part of the same transaction.

但是,如果我想并行处理这些插入片段以提高性能:

However, if I wanted to parallelize those inserts for performance:

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

然后,这些衍生的线程中的每个线程根本不会参与事务,因为事务是线程绑定的.

Then each one of those spawned threads will not participate in the transaction at all because transactions are Thread-bound.

关键问题:是否可以安全地将事务传播到子线程?

Key Question: Is there a way to safely propagate the transaction to the child threads?

我想到的唯一解决此问题的方法:

The only solutions I've thought of to solve this problem:

  1. 使用JTA或某些XA管理器,按照定义,它们应该能够执行 这.但是,理想情况下,我不想在解决方案中使用XA 因为有开销
  2. 将我要执行的所有事务性工作(在上面的示例中,为addNewRow()函数)放在单个线程中,并以多线程方式完成所有先前的工作.
  3. 找出某种方法来在事务状态上利用InheritableThreadLocal并将其传播到子线程.我不确定该怎么做.
  1. Use JTA or some XA manager, which by definition should be able to do this. However, I ideally don't want to use XA for my solution because of it's overhead
  2. Pipe all of the transactional work I want performed (in the above example, the addNewRow() function) to a single thread, and do all of the prior work in the multithreaded fashion.
  3. Figuring out some way to leverage InheritableThreadLocal on the Transaction status and propagate it to the child threads. I'm not sure how to do this.

还有其他解决方案吗?即使尝起来有点像变通办法(如我上面的解决方案)?

Are there any more solutions possible? Even if it's tastes a little bit of like a workaround (like my solutions above)?

推荐答案

首先,澄清一下:如果您想加速几个相同类型的插入(如您的示例所示),则可以通过发出在同一线程中插入 并使用某种类型的批量插入.根据您的DBMS,有几种可用的技术,请查看:

First, a clarification: if you want to speed up several inserts of the same kind, as your example suggests, you will probably get the best performance by issuing the inserts in the same thread and using some type of batch inserting. Depending on your DBMS there are several techniques available, look at:

  • Efficient way to do batch INSERTS with JDBC
  • What's the fastest way to do a bulk insert into Postgres?

关于您的实际问题,我个人将尝试将所有工作通过管道传递给工作线程.这是最简单的选项,因为您无需弄混ThreadLocal或事务登记/退市.此外,一旦将工作单元放在同一线程中,如果您很聪明,则可以应用上述批处理技术以获得更好的性能.

As for your actual question, I would personally try to pipe all the work to a worker thread. It is the simplest option as you don't need to mess with either ThreadLocals or transaction enlistment/delistment. Furthermore, once you have your units of work in the same thread, if you are smart you might be able to apply the batching techniques above for better performance.

最后,将工作管道传递给工作线程并不意味着您必须具有单个工作线程,您可以拥有一组工作线程并实现一些并行性(如果这对您的应用程序确实有利).从生产者/消费者的角度思考.

Lastly, piping work to worker threads does not mean that you must have a single worker thread, you could have a pool of workers and achieve some parallelism if it is really beneficial to your application. Think in terms of producers/consumers.

这篇关于跨多线程的单事务解决方案的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆