VerySource

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
12
返回列表 发新帖
楼主: missun

说说在处理WEB数据更新时,如何保证只有一个用户在编辑某一条记录?

[复制链接]

0

主题

29

帖子

16.00

积分

新手上路

Rank: 1

积分
16.00
发表于 2020-5-6 10:30:01 | 显示全部楼层
在查询的时候使用了with (UPDLOCK)选项,在查询记录的时候我们就对记录加上了更新锁,表示我们即将对次记录进行更新.注意更新锁和共享锁是不冲突的,也就是其他用户还可以查询此表的内容,但是和更新锁和排它锁是冲突的.所以其他的更新用户就会阻塞.如果我们在另外一个窗口执行此代码,同样不加waifor delay子句.两边执行完毕后,我们发现成功的注册了两张卡.可能我们已经发现了悲观锁定的缺点:当一个用户进行更新的事务的时候,其他更新用户必须排队等待,即使那个用户更新的不是同一条记录.
回复

使用道具 举报

0

主题

29

帖子

16.00

积分

新手上路

Rank: 1

积分
16.00
发表于 2020-5-6 15:15:01 | 显示全部楼层

乐观锁定解决方案

--  首先我们在Card表里边加上一列F_TimeStamp 列,该列是varbinary(8)类型.但是在更新的时候这个值会自动增长.

alter table Card add  F_TimeStamp timestamp not null


declare @CardNo varchar(20)
declare @timestamp varbinary(8)
declare @rowcount int

Begin Tran

       --  取得卡号和原始的时间戳值
        select top 1 @CardNo=F_CardNo,
                     @timestamp=F_TimeStamp
        from Card
        where F_Flag=0
        
        --  延迟50秒,模拟并发访问.
        waitfor delay '000:00:50'

        --  注册卡,但是要比较时间戳是否发生了变化.如果没有发生变化.更新成功.如果发生变化,更新失败.

        update Card
        set F_Name=user,
            F_Time=getdate(),
            F_Flag=1
        where F_CardNo=@CardNo and F_TimeStamp=@timestamp
        set @rowcount=@@rowcount
        if @rowcount=1
        begin
                print '更新成功!'
                commit
        end
        else if @rowcount=0
        begin
                if exists(select 1 from Card where F_CardNo=@CardNo)
                begin
                        print '此卡已经被另外一个用户注册!'
                        rollback tran
                end
                else
                begin
                        print '并不存在此卡!'
                        rollback tran
                end
        end
回复

使用道具 举报

0

主题

29

帖子

16.00

积分

新手上路

Rank: 1

积分
16.00
发表于 2020-5-6 17:45:01 | 显示全部楼层
在另外一个窗口里边执行没有waitfor的代码,注册成功后,返回原来的窗口,我们就会发现到时间后它显示的提示是此卡以被另外一个用户注册的提示.很明显,这样我们也可以避免两个用户同时注册一张卡的现象的出现.同时,使用这种方法的另外一个好处是没有使用更新锁,这样增加的系统的并发处理能力.
回复

使用道具 举报

0

主题

58

帖子

32.00

积分

新手上路

Rank: 1

积分
32.00
发表于 2020-5-6 20:30:02 | 显示全部楼层
你可以先把这条记录的id放到一个表中,编辑的时候先判断表中是否已经有id了,有的话表示记录正在编辑,编辑完成后然后把id从表中删除。 当然, 为了预防异常情况,你必须有解锁的功能。比方说,当id在出现异常的时候不能从表中删除,那你必须提供一个机制把这个id从表中删除。

另一种方式是加一个version列,每更新一次version就加1, 当然这种情况允许同时编辑,但更新的时候你可以选择覆盖更新还是拒绝更新。
回复

使用道具 举报

0

主题

11

帖子

8.00

积分

新手上路

Rank: 1

积分
8.00
发表于 2020-5-8 10:45:01 | 显示全部楼层
declare @CardNo varchar(20)
Begin Tran

       --  选择一张未使用的卡
        select top 1 @CardNo=F_CardNo
        from Card   with (UPDLOCK)  where F_Flag=0
        
        --  延迟50秒,模拟并发访问.
        waitfor delay '000:00:50'

       --  把刚才选择出来的卡进行注册.

        update Card
        set F_Name=user,
            F_Time=getdate(),
            F_Flag=1
        where F_CardNo=@CardNo

commit
回复

使用道具 举报

1

主题

4

帖子

5.00

积分

新手上路

Rank: 1

积分
5.00
 楼主| 发表于 2020-5-9 17:45:02 | 显示全部楼层
谢谢大家的回复,
首先说一下这是在WEB下处理,而不是WINFORM
我的需求是在其它人正在更新一条记录时其它用户就不允许更新此条记录,对于大家说的事务,如果使用锁,那么在客户异常退出时(是指关闭浏览器或关机),无法回滚事务。
回复

使用道具 举报

0

主题

32

帖子

22.00

积分

新手上路

Rank: 1

积分
22.00
发表于 2020-5-10 03:30:01 | 显示全部楼层
sql server和oracle都是用版本控制来实现事务的。
‘其它人正在更新一条记录时其它用户就不允许更新此条记录’这个只能让事务来控制(取决于具体的隔离级别),例如这个更新过程意外的很长,这时另一个人来更新,怎么办。他如何知道这个记录正在更新。
回复

使用道具 举报

1

主题

4

帖子

5.00

积分

新手上路

Rank: 1

积分
5.00
 楼主| 发表于 2020-7-7 23:30:01 | 显示全部楼层
还有什么好的建议?
回复

使用道具 举报

0

主题

9

帖子

6.00

积分

新手上路

Rank: 1

积分
6.00
发表于 2020-7-11 10:15:01 | 显示全部楼层
我有个笨方法,在数据库中再建个表,有ID,TABLENAME,TABLEID,如果你要是编辑类先判断在这个表是不是有了,没有就把某条类就插进去,再写个触发,过了5分钟就把某条删了,这样就不会死锁了,当你编辑完了也把这条删了,记得给分呀
回复

使用道具 举报

0

主题

2

帖子

3.00

积分

新手上路

Rank: 1

积分
3.00
发表于 2020-8-4 18:15:01 | 显示全部楼层
目的是什么?
为何不用[用户]加[时间]
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|CopyRight © 2008-2023|verysource.com ( 京ICP备17048824号-1 )

快速回复 返回顶部 返回列表