[英]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.