在多线程环境中处理事务

时间:2017-04-30 18:11:45

标签: java mysql multithreading jdbc

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

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

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

2 个答案:

答案 0 :(得分:2)

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

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

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

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

答案 1 :(得分:1)

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

  • 您的父处理线程将(1。)创建新线程以执行并行数据库插入,(2。)创建一个CountDownLatch对象(这将保留父线程,直到完成所有执行db插入的子线程为止(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,那么它可以通过其事务功能简化您的工作,但这会变成不同的故事。

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