[英]Concurrent use of same JDBC connection by multiple threads
我试图更好地了解如果多个线程尝试使用相同的 JDBC 连接同时执行不同的 sql 查询会发生什么。
结果在功能上是否正确?
性能影响是什么?
线程A
是否必须等待线程B
完成其查询?
或者线程A
能否在线程B
发送查询后立即发送其查询,之后数据库将并行执行两个查询?
我看到 Apache DBCP 使用同步协议来确保从池中获得的连接从池中删除,并使其不可用,直到它们关闭。 这似乎比它需要的更不方便。 我正在考虑通过创建一个静态的开放连接列表并以循环方式分发它们来构建我自己的“池”。
我不介意偶尔的性能下降,每次使用后不必关闭连接的便利似乎非常吸引人。 我这样做有什么缺点吗?
我使用 AWS RDS Postgres 数据库和 Java 11 运行了以下一组测试:
创建一个包含 1100 万行的表,每行包含一个 TEXT 列,填充随机的 100 个字符的字符串
随机选取一个5个字符的字符串,在上表中搜索该字符串的部分匹配项
Time 上述查询返回结果所需的时间。 就我而言,大约需要 23 秒。 因为返回的结果很少,我们可以得出结论,这 23 秒的大部分时间都花在等待数据库运行全表扫描上,而不是发送请求/响应数据包
使用不同的连接并行运行多个查询(使用不同的关键字)。 就我而言,我看到它们都在大约 23 秒内完成。 即,查询被有效地并行化
使用相同的连接在并行线程上运行多个查询。 我现在看到第一个结果在大约 23 秒后返回。 第二个结果在大约 46 秒后返回。 约 1 分钟内的第三个。 等等等等。所有结果在功能上都是正确的,因为它们匹配该线程查询的特定关键字
补充一下 Joni 之前提到的内容,他的结论也与我在 Postgres 上看到的行为相符。 如果同时在同一连接上发送多个查询,似乎保留了所有“正确性”,但所有并行性优势都将丢失。
由于 JDBC 规范不保证并发执行,因此只能通过测试您感兴趣的驱动程序或阅读它们的源代码来回答这个问题。
在 MySQL Connector/J 的情况下,所有execute
语句的方法都使用synchronized
块锁定连接。 也就是说,如果一个线程正在运行一个查询,使用该连接的其他线程将被阻塞,直到它完成。
以错误的方式做事会产生不确定的结果......如果有人运行一些测试,也许他们会准确地回答你所有的问题,但随后出现了一个新的 JVM,或者有人在另一个 jdbc 驱动程序或数据库版本上尝试它,或者他们遇到一组不同的竞争条件,或者尝试另一个平台或 JVM 实现,并且会发生另一个不同的未定义结果。
如果两个线程同时修改相同的状态,则任何事情都可能发生,具体取决于时间。 也许第二个会覆盖第一个查询,然后两者都运行相同的查询。 也许库会检测到您的错误并抛出异常。 我不知道也不会打扰测试......(或者可能有人已经知道或者应该很明显会发生什么)所以这不是“答案”,而只是一些建议。 只需使用连接池,或使用同步块来确保不会发生问题。
我们不得不禁用 Websphere 上的语句缓存,因为它在 PreparedStatement 级别抛出 ArrayOutOfBoundsException。 问题是有些人虽然与多个线程共享连接很聪明。 他说这是为了保存连接,但是多线程查询没有意义,因为数据库不会并行运行它们。
java runnables 也存在一个问题,因为它们使用相同的连接而相互阻塞。
所以这只是一些不做的事情,没有任何好处。
websphere 中有一个选项可以检测这种多线程访问。 我实现了自己的,因为我们在开发中使用码头。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.