简体   繁体   English

在多线程环境中处理事务

[英]Handling transaction in multithreaded environment

Need to insert data in database using multiple threads ,but even if a single thread fails to commit,all transaction must rollback.Tried to solve this by below approach. 需要使用多个线程在数据库中插入数据,但是即使单个线程提交失败,所有事务也必须回滚。尝试通过以下方法解决此问题。

Sharing connection object among thread,and using join() to wait for child thread to finish,but this looks like bad design,as i am sharing connection object among threads. 在线程之间共享连接对象,并使用join()等待子线程完成,但这看起来像是糟糕的设计,因为我正在线程之间共享连接对象。

Can someone suggest better design to solve this (Not sure should i go for distributed txn manager or not)? 有人可以建议更好的设计来解决此问题(不确定是否应使用分布式txn管理器)吗?

I would suggest to queue all SQL actions from multiple threads in some intermediate data structure, and then put into database from a single thread. 我建议将来自多个线程的所有SQL操作以某种中间数据结构排队,然后从单个线程放入数据库中。 It is possible to have the thread safe intermediate structures like ConcurrentHashMap , ConcurrentLinkedQueue or you may just synchronize when working with it. 可能具有线程安全的中间结构,例如ConcurrentHashMapConcurrentLinkedQueue或者您可以在使用它时进行同步。

This way you even do not need to start the transaction in advance. 这样,您甚至不需要提前启动事务。 The pending data may be less safe, but I assume they are not a lot safer in the database while the transaction is not committed yet. 暂挂的数据可能不太安全,但是我认为当事务尚未提交时,它们在数据库中的安全性并不高。

Of course, this can only work if you do not have select statements picking uncommitted transaction data from the same transaction. 当然,这仅在没有select语句从同一事务中选择未提交的事务数据的情况下才有效。 Getting rid of such queries one or another way may require redesign. 摆脱这种查询的一种或另一种方式可能需要重新设计。

Use CountDownLatch to detect when all data are ready and the database writing thread should start its action. 使用CountDownLatch可以检测所有数据何时准备就绪,并且数据库写入线程应开始其操作。 If never happens, use reactor pattern for the database writing thread. 如果永远不会发生,请对数据库写入线程使用反应堆模式。

Here are my quick thoughts with possible implementation steps: 这是我对可能的实现步骤的快速思考:

  • Your parent processing thread will (1.) create new threads to do parallel DB inserts, (2.) create a CountDownLatch object (this will hold your parent thread until all child threads which are doing db inserts are finished) (3.) create a db connection object with auto commit mode as FALSE. 您的父处理线程将(1.)创建新线程以执行并行DB插入, (2。)创建CountDownLatch对象(这将保留您的父线程,直到完成数据库插入的所有子线程都完成) (3.)创建自动提交模式为FALSE的数据库连接对象。
    • Suppose you are spawning 6 threads to do parallel DB inserts then you will create CountDownLatch object like this CountDownLatch countDownLatch = new CountDownLatch(6) and then spawn your parallel threads and do countDownLatch.await() 假设您正在生成6个线程以进行并行DB插入,然后将创建CountDownLatch对象,例如CountDownLatch countDownLatch = new CountDownLatch(6) ,然后生成并行线程并执行countDownLatch.await()
  • Your parallel threads will start inserting into DB, but key thing is that each of them is using db connection object in auto commit FALSE mode which was provided by parent thread, so basically no child thread will do the db commit. 您的并行线程将开始插入数据库,但关键是它们中的每个线程都在父线程提供的自动提交FALSE模式下使用数据库连接对象,因此基本上没有子线程会执行数据库提交。
    • Once each child thread is done they will do countDownLatch.countDown(); 一旦每个子线程完成,它们将执行countDownLatch.countDown(); to decrement the latching counter. 减少锁存计数器。
    • Please note that you need to make available the countDownLatch as well as db connection object to each thread, I am sure you would know how. 请注意,您需要为每个线程提供countDownLatch以及db连接对象,我相信您会知道。
  • Once latch counter reaches 0, your parent thread execution will start again (until latch counter is not 0, countDownLatch.await() will hold the thread) and then (1.) you can decide whether to commit or not based on result from each thread (2.) close the connection object. 一旦闩锁计数器达到0,您的父线程执行将再次开始(直到闩锁计数器不为0, countDownLatch.await()将保持该线程),然后(1.)您可以根据每个线程的结果来决定是否提交线程(2.)关闭连接对象。 Now, Runnable doesn't return anything so better use Callable so that each thread can inform about their status. 现在, Runnable不会返回任何内容,因此最好使用Callable以便每个线程都可以通知其状态。

If you are using Spring then it can ease your work with its transactional feature, but that becomes different story. 如果您使用的是Spring,那么它可以利用其事务功能简化您的工作,但是事情变得不同了。


Now, few points about what you mentioned in your question - you mentioned " even if a single thread fails to commit,all transaction must rollback ", basically if any of your db insert/access fails then you do not want to commit anything, so your Callable will return the status of their execution, I am not sure what else you could mean by this but I think if you have got the point about Callable then you should be fine. 现在,关于您在问题中提到的内容很少-您提到“ 即使单个线程提交失败,所有事务也必须回滚 ”,基本上,如果您的任何数据库插入/访问失败,那么您就不想提交任何内容,因此您的Callable会返回其执行状态,我不确定您所说的还有什么意思,但是我想,如果您对Callable有所了解,那您就可以了。 Also, you mentioned " but this looks like bad design,as i am sharing connection object among threads. ", you will need to share the db connection object because once a transaction is committed you cannot rollback, so it you do not want to share the connection object then probably you need to have set of SQL statement to undo the work done by earlier db access and their commits. 另外,您提到“ 但是这看起来像是糟糕的设计,因为我正在线程之间共享连接对象。 ”,您将需要共享数据库连接对象,因为一旦提交事务就无法回滚,因此您不希望共享那么,连接对象可能需要设置一组SQL语句来撤消早期数据库访问及其提交所完成的工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM