[英]JDBC transactions in multi-threaded environment
開發在多個線程之間共享單個連接的Java應用程序時,會出現並發問題。
如果線程A更新表T中的記錄1,並且線程B同時對表T中的記錄1發出SELECT,我如何確保線程B讀取線程A的更新值?
java.sql.Connection提供帶有begin(),commit()和rollback()的事務,但是此過程還涵蓋數據正確性嗎?
我想我缺少了一些東西。
兩點:
jdbc.Connection
,至少對於任何“嚴重生產”代碼而言,請參見此處 。 出於演示目的,我認為共享連接是可以的; 關於第二個問題
將線程B超時,直到第一個事務具有commit()或rollback()
-在以下情況下, B
將阻塞直到A
tx完成(通過提交或回滾):
B
嘗試更新/刪除A
正在更新的同一表行,然后... A
更新,下DB級鎖行,使用SELECT ... FOR UPDATE
。 您可以使用兩個控制台(例如,使用PostgreSQL psql
)來獲得此行為,每個控制台代表一個線程:
在A
控制台類型如下:
BEGIN;
SELECT some_col FROM some_tbl WHERE some_col = some_val FOR UPDATE;
現在在B
控制台中輸入:
BEGIN;
UPDATE some_tbl SET some_col = new_val WHERE some_col = some_val;
您應該看到UPDATE
塊,直到在A
執行COMMIT
或ROLLBACK
為止。
上面的解釋使用了單獨的數據庫連接,就像Java JDBC連接池一樣。 我認為,當您在Java線程之間共享單個連接時,如果其他某個線程使用了連接,則與DB的任何交互都會阻塞。
Jdbc是被廣泛采用的標准,但是遵循的標准不均衡,因此對安全性進行大膽的陳述可能不好。
我不希望有任何方法可以防止語句執行以及由多個線程進行的提交和回滾被交錯。 最好的情況是,一次只有一個線程可以使用該連接,而其他線程則阻塞,從而使多線程無用。
如果您不想提供與每個線程的連接,則可以讓線程將工作項提交到隊列,該隊列由處理所有jdbc工作的單個工作線程使用。 但是引入連接池對現有代碼的影響可能較小。
通常,如果您具有並發更新和讀取,則它們將按照發生的順序發生。 鎖定和隔離級別為並發事務提供了一致性保證,但是如果尚未開始其事務但這些事務將不適用。 您可能在每行上都有狀態標志,版本號或時間戳,以指示何時發生更新。
如果您有很多更新,最好將它們收集在一個平面文件中並執行批量復制。 它可能比使用jdbc快得多。 然后在不進行更新的情況下在jdbc中執行select。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.