【问题标题】:How to create a database deadlock using jdbc and JUNIT如何使用 jdbc 和 JUNIT 创建数据库死锁
【发布时间】:2011-02-06 18:52:45
【问题描述】:

我正在尝试创建数据库死锁并且我正在使用 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。

【问题讨论】:

  • 如何同时运行两种测试方法? JUnit 正在按顺序执行测试方法。
  • 我有两个 JUnit 测试用例并运行一个,然后切换到另一个并运行那个,它显示它们都在运行。
  • 我明白了。您使用的是什么事务隔离级别?
  • 那是我没有设置的。我不确定这意味着什么,但我记得教授告诉我们不要更改交易的超时时间。我不确定这是否相关。

标签: java jdbc junit derby


【解决方案1】:

您应该检查事务隔离级别,因为它决定了数据库是否锁定了事务所触及的行。如果隔离级别太低,则不会发生锁定,因此也不会出现死锁。

更新: 根据this page,Derby 的默认 tx 隔离级别是已提交读,应该没问题。顺便说一句,该页面值得一读,因为它解释了 tx 隔离及其不同级别,以及它解决了哪些问题。

接下来的问题是:您的代码中的DataBase 是什么?这似乎是一种非标准的连接方式。

Update2:我想我明白了。引用the API doc:

注意:默认情况下,Connection 对象处于自动提交模式,这意味着它会在执行每条语句后自动提交更改。如果自动提交模式已被禁用,则必须显式调用 commit 方法以提交更改;否则,数据库更改将不会被保存。

换句话说,行不会被锁定,因为您的有效事务仅在单个更新的生命周期内持续。您应该在开始使用您的连接之前关闭自动提交:

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

【讨论】:

  • 好的,所以一定是我正在做的事务不是导致死锁的类型。我不知道还能尝试什么,所以我得再读一些。
  • 我有一个名为“DataBase”的类,其中包含我所有的方法。其中之一是getConnection。它只是使用来自 JDBC 的 DriverManager.getConnection(url) 方法。
  • 更新:我得到的实际上只是一个锁定超时。没有发生死锁,我很确定这不是代码,因为我尝试了互联网上的各种死锁示例。一定是 JUnit 的一些设置。
  • @Isawpalmetto 或数据库。我猜数据库检测到无法获取锁并在经过一定时间后中断事务。我前段时间也观察到了。
  • @Isawpalmetto 这确实是德比的情况——见db.apache.org/derby/docs/10.0/manuals/develop/develop75.html
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-04
  • 1970-01-01
  • 1970-01-01
  • 2012-09-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多