Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 多线程并发使用相同的JDBC连接_Java_Jdbc_Database Connection_Connection Pooling_Apache Commons Dbcp - Fatal编程技术网

Java 多线程并发使用相同的JDBC连接

Java 多线程并发使用相同的JDBC连接,java,jdbc,database-connection,connection-pooling,apache-commons-dbcp,Java,Jdbc,Database Connection,Connection Pooling,Apache Commons Dbcp,我试图更好地理解如果多个线程试图同时使用同一个JDBC连接执行不同的sql查询,将会发生什么 结果在功能上是否正确 性能影响是什么 线程A是否必须等待线程B完成查询 或者线程A是否能够在线程B发送查询后立即发送查询,然后数据库将并行执行这两个查询 我看到ApacheDBCP使用同步协议来确保从池中获得的连接从池中删除,并使其不可用,直到它们关闭为止。这似乎比需要的更不方便。我正在考虑建立自己的“池”,只需创建一个静态的开放连接列表,并以循环方式分发它们 我不介意偶尔性能下降,每次使用后不必

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

  • 结果在功能上是否正确

  • 性能影响是什么

  • 线程
    A
    是否必须等待线程
    B
    完成查询

  • 或者线程
    A
    是否能够在线程
    B
    发送查询后立即发送查询,然后数据库将并行执行这两个查询


我看到ApacheDBCP使用同步协议来确保从池中获得的连接从池中删除,并使其不可用,直到它们关闭为止。这似乎比需要的更不方便。我正在考虑建立自己的“池”,只需创建一个静态的开放连接列表,并以循环方式分发它们


我不介意偶尔性能下降,每次使用后不必关闭连接的便利性似乎非常吸引人。我这样做有什么坏处吗?

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


如果两个线程同时修改相同的状态,根据时间的不同,任何事情都可能发生。也许第二个会覆盖第一个的查询,然后两个都运行相同的查询。可能库会检测到您的错误并引发异常。我不知道,也不会费心测试。。。(或者可能有人已经知道或者应该很明显会发生什么)所以这不是“答案”,只是一些建议。只需使用连接池,或使用同步块来确保问题不会发生。

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


在MySQL Connector/J的情况下,执行
语句的所有方法都使用
synchronized
块锁定连接。也就是说,如果一个线程正在运行一个查询,那么使用该连接的其他线程将被阻止,直到它完成为止。

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

java runnables也存在一个问题,因为它们使用相同的连接而相互阻塞

所以这只是一件不能做的事,没有任何好处

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

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

  • 创建一个包含11M行的表,每行包含一个文本列,并填充一个随机的100字符字符串

  • 在上表中随机选取一个5个字符的字符串,并搜索该字符串的部分匹配项

  • 上述查询返回结果所需的时间。在我的情况下,大约需要23秒。由于返回的结果非常少,因此我们可以得出结论,这23秒钟的大部分时间是等待数据库运行完整的表扫描,而不是发送请求/响应数据包

  • 使用不同的连接并行运行多个查询(使用不同的关键字)。在我的例子中,我看到它们都在23秒内完成。也就是说,查询正在高效地并行化

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


  • 再加上乔尼之前提到的,他的结论也与我在博士后身上看到的行为相符。如果在同一个连接上同时发送多个查询,那么所有“正确性”似乎都得到了保留,但所有并行性优势都将丢失。

    连接池远不止是一组连接。您应该真正了解连接池提供了什么。这里的参数可以提供一些我通过配置和接口上的其他API浏览过的提示,我对我的用例不感兴趣。因此,我最终编写了自己的实现,实现了大约10行代码,完全满足了我的需要,最大限度地减少了同步开销,并省去了在一百万个位置添加connection.close()的麻烦。在单个连接上多路复用多个线程是一个非常糟糕的主意。只需使用一个连接池,签出一个连接,并在完成后将其返回到连接池(关闭)。例如,您是否考虑过如果一个线程想要提交而另一个线程想要回滚会发生什么?您要么丢失数据,要么提交了错误的数据。那真是个糟糕的地方。另外,如果不使用
    Connection.close()
    ,您会让其他人不清楚您在做什么。使用PostgreSQL 42.2.5 JDBC驱动程序尝试这样做,两个线程都被阻止。JDBC连接规范是,关于发出和运行查询。我更关心的是性能方面的影响。我假设在这种情况下线程安全意味着它的所有方法都是安全的