Foxtable(狐表)用户栏目专家坐堂 → 网络环境下的工作流和并发冲突处理(高手必看,顺便测试一下)


  共有10925人关注过本帖树形打印复制链接

主题:网络环境下的工作流和并发冲突处理(高手必看,顺便测试一下)

帅哥哟,离线,有人找我吗?
狐狸爸爸
  1楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:管理员 帖子:47448 积分:251054 威望:0 精华:91 注册:2008/6/17 17:14:00
网络环境下的工作流和并发冲突处理(高手必看,顺便测试一下)  发帖心情 Post By:2010/4/9 16:39:00 [只看该作者]

本节的例子可以参考下面的附件

 下载信息  [文件大小:   下载次数: ]
图片点击可在新窗口打开查看点击浏览该文件:工作流.table


本节我们用一个最简单的例子来说明如何在网络环境下实现工作流,实际的工作流会比这个复杂,不过原理是一样的。
通过本节的内容,还可以掌握并发冲突的处理技巧,实现在网络环境下避免多人同时编译某行数据的任务。
本节并发冲突的处理技巧,和数据源无关,正因为不需要借助特定数据源的功能,所以通用性很强。


假定一个表有九列,分成三个工作流程来处理:

流程1处理一、二、三列
流程2处理四、五、六列
流程3处理七、八、九列


只有在上一流程已经处理完毕的情况下,才可以处理下一流程,例如只有输入一、二、三列的值后,才能输入四、五、六列的值。

本次设计要完成的任务为:

1、在针对某行处理一个流程前,首先自动检索改行的最新数据和流程处理进度,以决定能否处理此流程。
2、如果能够处理此流程,那么在开始处理之前先锁定此行,使得其他用户不能再处理此行,避免出现多个用户同时处理某一行的情况。
3、用户在处理完一个流程后,在保存处理结果的同时,还应该解锁行,使得其他用户可以处理此行。
4、为防止用户非正常退出后,出现死锁的情况,所以还应该提供强制解锁的功能。


提示:这是的锁定行,和我们之间介绍的锁定行是不同的,这里是在后台锁定某个行,使得其他用户不能编辑此行。


设计步骤:

1、首先我们需要加一个整数型的标记列,标记列的值等于1、2、3的时候,分别表示已经处理完成流程1、流程2、流程3,当标志列的值等于-1的时候,表示有人正在处理此行,也就是被锁定了。
2、将表锁定,避免用户直接在表中输入数据
3、增加一个选择流程的窗口,窗口的设计如下:



图片点击可在新窗口打开查看此主题相关图片如下:1251.gif
图片点击可在新窗口打开查看


按钮名称 代码
流程一 Dim r As Row = Tables("表A").Current
r.
DataRow.Load() '重新加载此行的数据
If
r.IsNull("标记") Then
   
Dim cmd as New SQLCommand
    cmd.CommandText =
"Update {表A} Set 标记 = -1 Where 标记 Is Null And [_Identify] = " & r("_Identify")
    If
cmd.ExecuteNonQuery = 1 Then
'防止并发冲突,上面的条件是很关键的
        Forms(
"流程1").Open()
    Else

        MessageBox.Show(
"其他用户已经抢先处理此行!")
    End
If
ElseIf
r("标记") = -1 Then
    Messagebox.Show(
"其他用户正在处理此行!")
Else

    MessageBox.Show(
"流程1已经完成!")
End
If
流程二 Dim r As Row = Tables("表A").Current
r.
DataRow.Load() '重新加载此行的数据
If
r.IsNull("标记") Then
    MessageBox.Show(
"流程1没有完成!")
ElseIf
r("标记") = 1 Then
    Dim cmd as New SQLCommand
    cmd.CommandText =
"Update {表A} Set 标记 = -1 Where 标记 = 1 And [_Identify] = " & r("_Identify")
    If
cmd.ExecuteNonQuery = 1 Then
'防止并发冲突,上面的条件是很关键的
       Forms(
"流程2").Open()
    Else

       MessageBox.Show(
"其他用户已经抢先处理此行!")
    End
If
ElseIf
r("标记") = -1 Then
    Messagebox.Show(
"其他用户正在处理此行!")
Else

    MessageBox.Show(
"流程2已经完成!")
End
If
流程三 Dim r As Row = Tables("表A").Current
r.
DataRow.Load() '重新加载此行的数据
If
r.IsNull("标记") OrElse r("标记") = 1 Then
    MessageBox.Show(
"流程2没有完成!")
ElseIf
r("标记") = 2 Then
   
Dim cmd as New SQLCommand
    cmd.CommandText =
"Update {表A} Set 标记 = -1 Where 标记 = 2 And [_Identify] = " & r("_Identify")
    If
cmd.ExecuteNonQuery = 1 Then
'防止并发冲突,上面的条件是很关键的
        Forms(
"流程3").Open()
    Else

        MessageBox.Show(
"其他用户已经抢先处理此行!")
    End
If
ElseIf
r("标记") = -1 Then
    Messagebox.Show(
"其他用户正在处理此行!")
Else

    MessageBox.Show(
"流程3已经完成!")
End
If
强制解锁(1) '强制解锁,并将流程设置为1
Dim
dr As DataRow = Tables("表A").Current.DataRow
Dim
cmd as New SQLCommand
cmd.CommandText =
"Update {表A} Set 标记 = 1 Where [_Identify] = " & dr("_Identify")
cmd.ExecuteNonQuery
dr.Load()
强制解锁(2) '强制解锁,并将流程设置为2
Dim
dr As DataRow = Tables("表A").Current.DataRow
Dim
cmd as New SQLCommand
cmd.CommandText =
"Update {表A} Set 标记 = 2 Where [_Identify] = " & dr("_Identify")
cmd.ExecuteNonQuery
dr.Load()
强制解锁(3) '强制解锁,并将流程设置为3
Dim
dr As DataRow = Tables("表A").Current.DataRow
Dim
cmd as New SQLCommand
cmd.CommandText =
"Update {表A} Set 标记 = 3 Where [_Identify] = " & dr("_Identify")
cmd.ExecuteNonQuery
dr.Load()
强制解锁(Null) '强制解锁,并将流程设置为初始状态
Dim
dr As DataRow = Tables("表A").Current.DataRow
Dim
cmd as New SQLCommand
cmd.CommandText =
"Update {表A} Set 标记 = Null Where [_Identify] = " & dr("_Identify")
cmd.ExecuteNonQuery

dr.Load()


提示:SQLCommand的
ExecuteNonQuery命令会返回一个整数值,表示受此命令影响的行数。


4、增加三个模式窗口,分别为流程1、流程2、流程3,用于处理各个流程,每个流程窗口的设计都是类似的,用于输入该流程应该处理的数据,例如流程2窗口的设计为:



图片点击可在新窗口打开查看此主题相关图片如下:1249.gif
图片点击可在新窗口打开查看


由于表是锁定的,所以流程窗口中文本框的只读属性应该设置为False,否则不能输入数据:



图片点击可在新窗口打开查看此主题相关图片如下:1250.gif
图片点击可在新窗口打开查看


给流程窗口的按钮设置代码,以流程2窗口为例:

按钮名称 代码
确定 With Tables("表A").Current
   
If .Isnull("第四列") OrElse .IsNull("第五列") OrElse .IsNull("第六列") Then
        MessageBox.Show(
"流程二没有处理完!")
       
Return
    End
If
End
With
Tables
("表A").Current("标记") = 2
DataTables("表A").Save()
e.Form.Close()
取消

Tables("表A").Current.DataRow.RejectChanges()
Tables
("表A").Current("标记") = 1
DataTables
("表A").Save()
e.Form.Close()


提示:为了防止用户跳过确定和取消按钮,直接关闭窗口,流程1、流程2、流程3三个窗口的允许关闭属性应该设置为False:



图片点击可在新窗口打开查看此主题相关图片如下:1252.gif
图片点击可在新窗口打开查看

防止并发冲突的原理

至此我们这个简单的工作流系统已经设计完成,本系统不仅能够实现工作流,而且可以防止并发冲突,从某用户开始编辑某行数据开始,任何人都不能编辑此行数据,直到该用户结束或取消编辑。
其实现的原理很简单,以某个用户准备对某行数据进行流程2处理为例,用户单击流程选择窗口的流程2按钮后,执行的代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Dim r As Row = Tables("表A").Current
r.
DataRow.Load() '重新加载此行的数据
If
r.IsNull("标记") Then
   MessageBox.Show(
"流程1没有完成!")
ElseIf
r("标记") = 1 Then
   Dim cmd as New SQLCommand
   cmd.CommandText =
"Update {表A} Set 标记 = -1 Where 标记 = 1 And [_Identify] = " & r("_Identify")
   If
cmd.ExecuteNonQuery = 1 Then
'防止并发冲突,上面的条件是很关键的
      Forms(
"流程2").Open()
   Else

      MessageBox.Show(
"其他用户已经抢先处理此行!")
   End
If
ElseIf
r("标记") = -1 Then
   Messagebox.Show(
"其他用户正在处理此行!")
Else

   MessageBox.Show(
"流程2已经完成!")
End
If


为便于讲解,我们对上面的代码进行了编号:


1、第2行代码重新加载此行,获得最新的数据和流程处理进度。
2、第3行代码判断流程进度是否为空,如果为空表示流程1没有处理完成,所以不能处理流程2;第5行代码判断当前进度是否等于1,如果等于1,表示可以处理流程2。
3、第6、7、8行是处理并发冲突的关键代码,用Update语句将当前行的标记列设置为-1,等于通知其他用户,我开始处理此行了;Update语句的条件设置是至关重要的,主键值条件的加入是当然的,也是必须的,大家都能理解,最关键的是“标记 = 1”的条件,假定A和B用户几乎在同一时间对同一行进行流程2处理,两个人在重新加载此行后,都得到了此行目前流程处理进度为1的信息,可以进行流程2的处理,于是两个人都试图用Update语句将当前行的标记设置为-1,但是只有一个人
的ExecuteNonQuery方法(第8行)返回值会等于-1;例如假定A用户抢先执行了第8行的代码,ExecuteNonQuery的返回值等于1,于是正常开始流程2的处理,B用户随后同样执行第8行代码,但由于此时标记列的内容已经等于-1,不符合第7行设置的条件之一“标记 = 1”,所以不会有任何符合条件的行,于是第8行的ExecuteNonQuery不等于1,不能正常进入流程2的处理。


上面
是进入流程的处理,下面讲讲退出流程的处理,以流程2窗口为例,该窗口的确定按钮代码为:

1
2
3
4
5
6
7
8
9
With Tables("表A").Current
   
If .Isnull("第四列") OrElse .IsNull("第五列") OrElse .IsNull("第六列") Then
        MessageBox.Show(
"流程二没有处理完!")
       
Return
    End
If
End
With
Tables
("表A").Current("标记") = 2
DataTables("表A").Save()
e.Form.Close()


上面的代码首先判断流程2是否正常处理完毕,然后第7行代码将当前行标记列的值设置为2,并保存数据,等于告诉其他用户:我已经处理完流程2了,你们可以进行后续处理工作了。


流程2窗口取消按钮的代码为:

1
2
3
4
Tables("表A").Current.DataRow.RejectChanges()
Tables
("表A").Current("标记") = 1
DataTables
("表A").Save()
e.Form.Close()


第1行代码撤销对当前行的修改,第2行代码将标记列的值设置为1,并保存数据,等于告诉其他用户:我放弃处理流程2了,流程进度重新回到1,你们可以继续处理此行了。


强制解锁


如果某个用户正在针对某行处理一个流程,此时因为断电或者其它原因导致非正常退出,那么此行的标记列内容将一直等于-1,任何人将不能再处理此行了,所以我们还应该提供“解锁”的功能,强行将标志列的内容设置为某个值。
例如下面的代码,将标志列的内容强行设置为2:


'强制解锁,并将流程设置为2

Dim
dr As DataRow = Tables("表A").Current.DataRow
Dim
cmd as New SQLCommand
cmd.CommandText =
"Update {表A} Set 标记 = 2 Where [_Identify] = " & dr("_Identify")

cmd.ExecuteNonQuery

dr.Load()


提示:实际应用的时候,应该设置为只有特定用户才能执行强制解锁功能。

[此贴子已经被作者于2010-4-9 16:39:55编辑过]

 回到顶部
帅哥哟,离线,有人找我吗?
baoxyang
  2楼 | QQ | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:狐精 帖子:3313 积分:23134 威望:0 精华:1 注册:2009/3/31 11:25:00
  发帖心情 Post By:2010/4/9 16:44:00 [只看该作者]

正需要,谢谢!!顶!!!


 回到顶部
帅哥哟,离线,有人找我吗?
kylin
  3楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信 F6
等级:狐精 帖子:3030 积分:19188 威望:0 精华:2 注册:2008/9/1 7:50:00
  发帖心情 Post By:2010/4/9 19:07:00 [只看该作者]

谢谢先,测试去,呵呵!


 回到顶部
帅哥哟,离线,有人找我吗?
卟离卟弃
  4楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:五尾狐 帖子:1181 积分:8108 威望:0 精华:1 注册:2009/1/17 10:52:00
  发帖心情 Post By:2010/4/9 20:52:00 [只看该作者]

首先,要感谢党,在感谢CCTV,感谢MTV..感谢AV...

我太需要了..


 回到顶部
帅哥哟,离线,有人找我吗?
程兴刚
  5楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信 一级勋章
等级:超级版主 帖子:7235 积分:40556 威望:0 精华:16 注册:2008/8/31 23:23:00
  发帖心情 Post By:2010/4/10 0:16:00 [只看该作者]

收藏,抽空再学习!

 回到顶部
帅哥哟,离线,有人找我吗?
blackzhu
  6楼 | QQ | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信 一级勋章
等级:狐仙 帖子:9875 积分:57584 威望:0 精华:15 注册:2008/9/1 9:45:00
  发帖心情 Post By:2010/4/10 10:30:00 [只看该作者]

学习

 回到顶部
帅哥哟,离线,有人找我吗?
liuruihua
  7楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:四尾狐 帖子:781 积分:9870 威望:0 精华:0 注册:2008/9/1 13:47:00
  发帖心情 Post By:2010/4/10 18:11:00 [只看该作者]

用户已被锁定

 回到顶部
帅哥哟,离线,有人找我吗?
xubing051018
  8楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:二尾狐 帖子:518 积分:4239 威望:0 精华:0 注册:2012/12/2 16:53:00
回复:(狐狸爸爸)网络环境下的工作流和并发冲突处理...  发帖心情 Post By:2014/2/9 14:56:00 [只看该作者]

请教....例子看了,为了防止并发操作,需要在表里加个"标志"列进行处理.....我想问,在不更改表结构的情况下如何实现独占式编辑.

比如我有个部门表.就部门编号,部门名称两列,在不增加表的数据列的情况下..如何写代码实现独占式编辑?


 回到顶部
帅哥哟,离线,有人找我吗?
blackzhu
  9楼 | QQ | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信 一级勋章
等级:狐仙 帖子:9875 积分:57584 威望:0 精华:15 注册:2008/9/1 9:45:00
  发帖心情 Post By:2014/2/9 15:15:00 [只看该作者]

啊 那个还没有搞定 测试代码没用吗?

 回到顶部
美女呀,离线,留言给我吧!
找到没重的名
  10楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:幼狐 帖子:129 积分:2193 威望:0 精华:0 注册:2016/11/8 6:22:00
  发帖心情 Post By:2021/3/20 17:31:00 [只看该作者]

有用,马克

 回到顶部