多个线程同时使用相同的JDBC连接

时间:2015-10-03 20:46:19

标签: java jdbc database-connection connection-pooling apache-commons-dbcp

我试图更好地理解如果多个线程同时使用相同的JDBC连接尝试执行不同的sql查询会发生什么。

  • 结果是否在功能上正确?

  • 性能影响是什么?

  • 线程A是否必须等待线程B完全使用其查询完成?

  • 或者线程A能够在线程B发送其查询后立即发送其查询,之后数据库将并行执行两个查询吗?

我看到Apache DBCP使用同步协议来确保从池中删除从池中获取的连接,并使其不可用,直到它们关闭。这似乎比它需要的更不方便。我正在考虑建立自己的游泳池"只需创建一个静态的打开连接列表,并以循环方式分发它们。我不介意偶尔的性能下降,并且在每次使用后不必关闭连接的便利性似乎非常吸引人。这样做有什么不好吗?

4 个答案:

答案 0 :(得分:2)

由于JDBC规范并未保证并发执行,因此只能通过测试您感兴趣的驱动程序或阅读其源代码来解答此问题。

对于MySQL Connector / J,execute语句的所有方法都锁定了与synchronized块的连接。也就是说,如果一个线程正在运行查询,则使用该连接的其他线程将被阻塞,直到完成。

答案 1 :(得分:1)

我使用AWS RDS Postgres数据库和Java 11运行了以下测试:

  1. 创建一个包含11M行的表,每行包含一个TEXT列,并填充一个随机的100个字符的字符串

  2. 选择一个随机的5个字符串,然后在上表中搜索该字符串的部分匹配项

  3. 以上查询返回结果所需的时间。就我而言,大约需要23秒。由于返回的结果很少,我们可以得出结论,这23秒的大部分时间都花在等待数据库运行全表扫描上,而不是在发送请求/响应包上

  4. 使用不同的连接并行运行多个查询(使用不同的关键字)。就我而言,我看到它们都在约23秒内完成。即,查询正在有效地并行化

  5. 使用相同的连接在并行线程上运行多个查询。现在,我看到第一个结果将在约23秒后返回。第二个结果将在约46秒后返回。大约1分钟内的第三个。等等。所有结果在功能上都是正确的,因为它们与该线程查询的特定关键字匹配

要补充Joni先前提到的内容,他的结论也与我在Postgres上看到的行为相符。似乎保留了所有“正确性”,但是,如果同时在同一连接上发送多个查询,则会失去所有并行性的好处。

答案 2 :(得分:0)

以错误的方式做事会产生不确定的结果......如果有人运行某些测试,也许他们会准确回答你的所有问题,但是然后会出现一个新的JVM,或者有人在另一个jdbc驱动程序上尝试数据库版本,或者他们遇到一组不同的竞争条件,或尝试另一个平台或JVM实现,并发生另一个不同的未定义结果。

如果两个线程同时修改相同的状态,则可能会发生任何事情,具体取决于时间。也许第二个覆盖了第一个查询,然后两个都运行相同的查询。也许库会检测到您的错误并抛出异常。我不知道也不会打扰测试...(或者某人已经知道或者应该明白会发生什么)所以这不是答案",但只是一些建议。只需使用连接池,或使用同步块来确保不会发生问题。

答案 3 :(得分:0)

我们必须在Websphere上禁用语句缓存,因为它在PreparedStatement级别抛出了ArrayOutOfBoundsException。 问题是有些人虽然很聪明地与多个线程共享连接。 他说这是为了保存连接,但是多线程查询没有意义,因为db不会并行运行它们。

由于他们使用了相同的连接,因此java runnables也存在阻塞彼此的问题。

所以这只是不做的事情,没有什么可以获得的。

websphere中有一个选项可以检测此多线程访问。 我实施了自己的,因为我们在开发中使用了jetty。