在multithreading环境中处理事务

需要使用多个线程在数据库中插入数据,但即使单个线程无法提交,也必须回滚所有事务。请通过以下方法解决此问题。

在线程之间共享连接对象,并使用join()等待子线程完成,但这看起来像糟糕的设计,因为我在线程之间共享连接对象。

有人可以建议更好的设计来解决这个问题(不确定我是否应该选择分布式txn管理器)?

我建议将一些中间数据结构中的多个线程的所有SQL操作排队,然后从单个线程放入数据库。 可以使用ConcurrentHashMapConcurrentLinkedQueue等线程安全的中间结构,或者在使用它时可以只进行同步。

这样您甚至不需要提前启动事务。 挂起的数据可能不太安全,但我认为它们在数据库中并不是很安全,而事务尚未提交。

当然,只有在没有select语句从同一事务中选择未提交的事务数据时,这才能起作用。 以一种或另一种方式摆脱这些查询可能需要重新设计。

使用CountDownLatch检测所有数据何时就绪并且数据库写入线程应该开始其操作。 如果从未发生过,请将reactor模式用于数据库写入线程。

以下是我对可能的实施步骤的快速思考:

  • 您的父处理线程将(1.)创建新线程以执行并行数据库插入, (2)创建一个CountDownLatch对象(这将保留您的父线程,直到所有正在执行数据库插入的子线程完成) (3)创建具有自动提交模式的数据库连接对象为FALSE。
    • 假设您正在生成6个线程来执行并行数据库插入,那么您将创建CountDownLatch对象,如此CountDownLatch countDownLatch = new CountDownLatch(6)然后生成并行线程并执行countDownLatch.await()
  • 您的并行线程将开始插入数据库,但关键是它们每个都在父线程提供的自动提交FALSE模式下使用数据库连接对象,所以基本上没有子线程将执行数据库提交。
    • 每个子线程完成后,它们将执行countDownLatch.countDown(); 递减锁存计数器。
    • 请注意,您需要为每个线程提供countDownLatch和db连接对象,我相信您会知道如何。
  • 一旦锁存计数器达到0,你的父线程执行将再次开始(直到锁存计数器不为0, countDownLatch.await()将保持线程)然后(1.)你可以决定是否提交基于每个的结果线程(2.)关闭连接对象。 现在, Runnable不会返回任何内容,因此最好使用Callable以便每个线程都能告知其状态。

如果您正在使用Spring,那么它可以通过其事务function简化您的工作,但这会变成不同的故事。


现在,关于你在问题中提到的内容几点 – 你提到“ 即使单个线程无法提交,所有事务都必须回滚 ”,基本上如果你的任何db插入/访问失败那么你不想提交任何东西,所以你的Callable将返回他们执行的状态,我不知道你还有什么意思,但我认为如果你对Callable有所了解那么你应该没问题。 此外,你提到“ 但这看起来像糟糕的设计,因为我在线程之间共享连接对象。 ”,你需要共享数据库连接对象,因为一旦事务提交你就无法回滚,所以你不想共享然后,连接对象可能需要有一组SQL语句来撤消早期数据库访问及其提交所完成的工作。