2010-04-11 33 views
1

我想創建一個數據庫死鎖,並且正在使用JUnit。我有兩個併發的測試運行,它們都在循環中反覆更新表中的同一行。如何使用jdbc和JUNIT創建數據庫死鎖

我的想法是,你在一次測試中一次又一次地更新表A中的A行,然後B表中的B行。然後同時更新行B表B,然後重複更新A行表A。根據我的理解,這最終會導致僵局。

這裏是代碼第一次測試。

public static void testEditCC() 
{ 
    try{ 
     int rows = 0; 
     int counter = 0; 
     int large=10000000; 
     Connection c=DataBase.getConnection(); 
     while(counter<large) 
     { 
      int pid = 87855; 
      int cCode = 655; 
      String newCountry="Egypt";    
      int bpl = 0; 
      stmt = c.createStatement(); 

      rows = stmt.executeUpdate("UPDATE main " +    //create lock on main table 
                "SET BPL="+cCode+ 
                "WHERE ID="+pid); 
      rows = stmt.executeUpdate("UPDATE BPL SET DESCRIPTION='SomeWhere' WHERE ID=602"); //create lock on bpl table 
      counter++; 
     } 

     assertTrue(rows == 1); 
     //rows = stmt.executeUpdate("Insert into BPL (ID, DESCRIPTION) VALUES ("+cCode+", '"+newCountry+"')"); 

    } 
    catch(SQLException ex) 
    { 
     ex.printStackTrace(); 
     //ex.getMessage(); 
    } 
} 

這裏是第二個測試的代碼。

public static void testEditCC() 
{ 
    try{ 
     int rows = 0; 
     int counter = 0; 
     int large=10000000; 
     Connection c=DataBase.getConnection(); 
     while(counter<large) 
     { 
      int pid = 87855; 
      int cCode = 655; 
      String newCountry="Jordan";   
      int bpl = 0; 
      stmt = c.createStatement(); 
      //stmt.close(); 
      rows = stmt.executeUpdate("UPDATE BPL SET DESCRIPTION='SomeWhere' WHERE ID=602"); //create lock on bpl table 
      rows = stmt.executeUpdate("UPDATE main " +   //create lock on main table 
                "SET BPL="+cCode+ 
                "WHERE ID="+pid); 
      counter++; 
     } 

     assertTrue(rows == 1); 
     //rows = stmt.executeUpdate("Insert into BPL (ID, DESCRIPTION) VALUES ("+cCode+", '"+newCountry+"')"); 

    } 
    catch(SQLException ex) 
    { 
     ex.printStackTrace(); 
    } 
} 

我在同一時間運行兩個獨立的JUnit測試,並正在連接到,我在網絡模式運行在Eclipse的Apache Derby數據庫。任何人都可以幫我弄清楚爲什麼僵局不會發生?也許我正在使用JUnit錯誤。

+0

您如何在同一時間運行兩種測試方法? JUnit正在按順序執行測試方法。 – 2010-04-11 19:49:08

+0

我有兩個JUnit測試用例並運行一個,然後切換到另一個並運行該測試用例,並顯示它們都在運行。 – Isawpalmetto 2010-04-11 19:53:37

+0

我明白了。您使用的是什麼事務隔離級別? – 2010-04-11 19:55:45

回答

1

您應該檢查事務隔離級別,因爲它確定數據庫是否鎖定事務觸發的行。如果隔離級別太低,則不會發生鎖定,因此無死鎖。

更新:根據this page,Derby的默認tx隔離級別被讀取提交,這應該是確定的。該頁面值得一讀,因爲它解釋了tx隔離及其不同級別,以及它解決的問題。

接下來的問題是:什麼是DataBase在你的代碼?這似乎是獲得連接的非標準方式。

Update2:我想我明白了。從the API doc報價:

注意:默認情況下,Connection對象處於自動提交模式下,這意味着它會自動提交執行每個語句後的變化。如果禁用了自動提交模式,則必須顯式調用方法提交以提交更改;否則,數據庫更改將不會保存。

換句話說,行未被鎖定,因爲您的有效事務僅持續到單個更新的生命週期。在開始使用連接之前,您應該關閉自動提交功能:

Connection c=DataBase.getConnection(); 
c.setAutoCommit(false); 
+0

好吧,所以它必須是我所做的事務不是導致死鎖的類型。我不知道還有什麼可以嘗試的,所以我將不得不做更多的閱讀。 – Isawpalmetto 2010-04-11 20:22:03

+0

我有一個名爲「DataBase」的類,它包含我所有的方法。其中之一是getConnection。它只是使用JDBC中的DriverManager.getConnection(url)方法。 – Isawpalmetto 2010-04-11 20:28:24

+0

@Isawpalmetto好吧,我想我明白了 - 看看我最近的更新。 – 2010-04-11 20:35:03