我正在尝试创建数据库死锁,我正在使用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 :(得分:1)
您应该检查事务隔离级别,因为它确定数据库是否锁定事务所触及的行。如果隔离级别太低,则不会发生锁定,因此也没有死锁。
更新:根据this page,读取了Derby的默认tx隔离级别,这应该没问题。该页面值得阅读btw,因为它解释了tx隔离及其不同的级别,以及它解决了什么问题。
接下来的问题:代码中的DataBase
是什么?这似乎是一种非标准的连接方式。
Update2:我想我明白了。引自the API doc:
注意:默认情况下,Connection对象处于自动提交模式,这意味着它在执行每个语句后自动提交更改。如果已禁用自动提交模式,则必须显式调用方法commit才能提交更改;否则,数据库更改将不会保存。
换句话说,行未锁定,因为您的有效事务仅在单个更新的生命周期中持续存在。您应该在开始使用连接之前关闭自动提交:
Connection c=DataBase.getConnection();
c.setAutoCommit(false);