2010-04-11 38 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