我正在在AS400上使用DB2 iSeries迁移遗留应用程序,该应用程序具有特定的行为,我必须使用.NET和.NET的DB2.Data.DB2.iSeries客户端来复制这些行为。 我所描述的内容对非DB2非AS400的我来说适用,但是在AS400 DB2中,它取代了我要替换的旧应用程序-但不适用于我的应用程序。
原始应用程序中的行为:
在我的.NET代码中,我有两个问题:
步骤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");
}
}
运行两次此代码-您将看到两个进程都到达“此行应被锁定”,这就是我要描述的问题。
期望的结果是,第一个进程将到达“该行应被锁定”,而第二个进程将因资源繁忙错误而失败。
然后,当第一个进程到达第二个消息框时-“该行应被解锁”,第二个进程(再次运行后)将到达“该行应被锁定”消息。
任何帮助将不胜感激
答案 0 :(得分:0)
使用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");
}
}
我们不喜欢它-但却可以。