DB2 iSeries 未锁定 select 以进行更新

DB2 iSeries doesn't lock on select for update

我正在使用 AS400 上的 DB2 iSeries 迁移遗留应用程序,它具有我必须使用 .NET 和 DB2.Data.DB2.iSeries .NET 客户端重现的特定行为。 我所描述的适用于 DB2 非 AS400,但在 AS400 DB2 中,它适用于我正在替换的遗留应用程序 - 但不适用于我的应用程序。

原始应用程序中的行为:

  1. 开始交易
  2. 执行Reader () => Select table1 中的 col1,其中 col1 = 1 用于更新。
  3. 该行现已锁定。任何其他尝试 运行 Select 更新的人都应该失败。
  4. 关闭第 2 行打开的 Reader。
  5. 该行现已解锁。 - 任何其他尝试 运行 select 更新的人应该会成功。
  6. 结束交易,从此过上幸福的生活。

在我的 .NET 代码中有两个问题:

  1. 第 2 步 - 仅检查该行是否已被锁定 - 但实际上并未锁定它。所以另一个用户可以 运行 select 进行更新 - 错误行为

  2. 一旦成功 - 我需要锁在 reader 关闭时解锁(第 4 步)

这是我的代码:

var cb = new IBM.Data.DB2.iSeries.iDB2ConnectionStringBuilder();
cb.DataSource = "10.0.0.1";
cb.UserID = "User";
cb.Password = "Password";
using (var con = new IBM.Data.DB2.iSeries.iDB2Connection(cb.ToString()))
{

    con.Open();
    var t = con.BeginTransaction(System.Data.IsolationLevel.ReadUncommitted);
    using (var c = con.CreateCommand())
    {
        c.Transaction = t;
        c.CommandText = "select col1 from table1 where col1=1 FOR UPDATE";
        using (var r = c.ExecuteReader())
        {
            while (r.Read()) {
                MessageBox.Show(con.JobName +  "The Row Should Be Locked");
            }
        }
        MessageBox.Show(con.JobName +  "The Row Should Be unlocked");
    }
}

当你 运行 这段代码两次时 - 你会看到两个进程都到达 "This row should be locked" 这就是我正在描述的问题。

期望的结果是第一个进程将到达 "This row should be locked" 而第二个进程将因资源繁忙错误而失败。

然后当第一个进程到达第二个消息框时 - "the row should be unlocked" 第二个进程(再次 运行ning 之后)将到达 "This row should be locked" 消息。

任何帮助将不胜感激

documentation 说:

When the UPDATE clause is used, FETCH operations referencing the cursor acquire an exclusive row lock.

这意味着正在使用游标,并且在执行fetch 语句时发生锁定。我在您的代码中没有看到光标或提取。

现在,我不知道 .NET 是否将其作为游标来处理,但 DB2 UDB 文档没有这种表示法。

Isolation Level 允许这种行为。读取锁定的行。

读取未提交 脏读是可能的,这意味着没有共享锁被发布并且没有独占锁被接受。

经过大量调查后,我们以存储过程的形式创建了一个解决方法,为我们执行锁定。

存储过程如下所示:

CREATE PROCEDURE lib.Select_For_Update  (IN SQL CHARACTER (5000) ) 
    MODIFIES SQL DATA CONCURRENT ACCESS RESOLUTION WAIT FOR OUTCOME 
    DYNAMIC RESULT SETS 1 OLD SAVEPOINT LEVEL COMMIT ON RETURN 
    NO DISALLOW DEBUG MODE SET OPTION COMMIT = *CHG BEGIN
DECLARE X CURSOR WITH RETURN TO CLIENT FOR SS ;
PREPARE SS FROM SQL ;
OPEN X ;
END 

然后我们调用它:

var cb = new IBM.Data.DB2.iSeries.iDB2ConnectionStringBuilder();
cb.DataSource = "10.0.0.1";
cb.UserID = "User";
cb.Password = "Password";
using (var con = new IBM.Data.DB2.iSeries.iDB2Connection(cb.ToString()))
{

    con.Open();
    var t = con.BeginTransaction(System.Data.IsolationLevel.ReadUncommitted);
    using (var c = con.CreateCommand())
    {
        c.Transaction = t;
        c.CommandType = CommandType.StoredProcedure;
        c.AddParameter("sql","select col1 from table1 where col1=1 FOR UPDATE");
        c.CommandText = "lib.Select_For_Update"
        using (var r = c.ExecuteReader())
        {
            while (r.Read()) {
                MessageBox.Show(con.JobName +  "The Row Should Be Locked");
            }
        }
        MessageBox.Show(con.JobName +  "The Row Should Be unlocked");
    }
}

我们不喜欢它 - 但它有效。