DB2 iSeries不会锁定选择更新

时间:2018-06-27 13:11:14

标签: db2-400

我正在在AS400上使用DB2 iSeries迁移遗留应用程序,该应用程序具有特定的行为,我必须使用.NET和.NET的DB2.Data.DB2.iSeries客户端来复制这些行为。 我所描述的内容对非DB2非AS400的我来说适用,但是在AS400 DB2中,它取代了我要替换的旧应用程序-但不适用于我的应用程序。

原始应用程序中的行为:

  1. 开始交易
  2. ExecuteReader()=>从表1中选择col1,其中col1 = 1进行更新。
  3. 该行现已锁定。尝试运行“选择更新”的任何其他人都应该失败。
  4. 关闭第2行中打开的阅读器。
  5. 该行现已解锁。 -其他尝试运行select进行更新的人都应该成功。
  6. 完成交易并从此过上幸福的生活。

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

  1. 步骤2-仅检查该行是否已被锁定-但实际上并未锁定它。因此另一个用户可以并且确实选择运行更新-错误行为

  2. 一旦可行-当阅读器关闭时,我需要锁才能解锁(步骤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");
    }
}

运行两次此代码-您将看到两个进程都到达“此行应被锁定”,这就是我要描述的问题。

期望的结果是,第一个进程将到达“该行应被锁定”,而第二个进程将因资源繁忙错误而失败。

然后,当第一个进程到达第二个消息框时-“该行应被解锁”,第二个进程(再次运行后)将到达“该行应被锁定”消息。

任何帮助将不胜感激

3 个答案:

答案 0 :(得分:0)

documentation说:

  

使用UPDATE子句时,引用游标的FETCH操作将获得排他的行锁。

这意味着正在使用游标,并且在执行fetch语句时发生锁定。我看不到光标,也看不到代码。

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

答案 1 :(得分:0)

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

未提交读 可能会进行脏读,这意味着不会发出共享锁,也不会使用独占锁。

答案 2 :(得分:0)

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

存储过程如下:

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");
    }
}

我们不喜欢它-但却可以。