`
yizhyi
  • 浏览: 61500 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

SQL SERVER乐观锁定和悲观锁定使用实例

阅读更多

乐观锁定,悲观锁定,锁

 

在实际的多用户并发访问的生产环境里边,我们经常要尽可能的保持数据的一致性。而其中
最典型的例子就是我们从表里边读取数据,检查验证后对数据进行修改,然后写回到数据库
中。在读取和写入的过程中,如果在多用户并发的环境里边,其他用户已经把你要修改的数据
进行了修改是非常有可能发生的情况,这样就造成了数据的不一致性。解决这样的办法,SQL SERVER
提出了乐观锁定和悲观锁定的概念,下边我以一个实例来说明如何使用乐观锁定和悲观锁定来
解决这样的问题。

/* 建立测试表:Card,代表一个真实的卡库,供用户注册.用户要从里边选出一个未使用的卡,也就是F_Flag=0的卡,给用户注册:更新F_Name,F_Time,F_Flag字段. 如果出现两个用户同时更新一张卡的情况,是不能容忍的,也就是我们所说的数据不一致行。*/

create table Card(F_CardNO varchar(20),F_Name varchar(20),F_Flag bit,F_Time datetime)
Go
insert Card(F_CardNo,F_Flag) select '1111-1111',0
insert Card(F_CardNo,F_Flag) select '1111-1112',0
insert Card(F_CardNo,F_Flag) select '1111-1113',0
insert Card(F_CardNo,F_Flag) select '1111-1114',0
insert Card(F_CardNo,F_Flag) select '1111-1115',0
insert Card(F_CardNo,F_Flag) select '1111-1116',0
insert Card(F_CardNo,F_Flag) select '1111-1117',0
insert Card(F_CardNo,F_Flag) select '1111-1118',0
insert Card(F_CardNo,F_Flag) select '1111-1119',0
insert Card(F_CardNo,F_Flag) select '1111-1110',0
Go

--  下边是我们经常使用的更新方案如下:


declare @CardNo varchar(20)
Begin Tran

       --  选择一张未使用的卡
        select top 1 @CardNo=F_CardNo
        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

commit

问题:如果我们在同一窗口执行同一段代码,但是去掉了waitfor delay子句.两边执行完毕后 我们发现尽管执行了两次注册,但是只注册了一张卡,也就是两个人注册了同一张卡. 

悲观锁定解决方案

--  我们只要对上边的代码做微小的改变就可以实现悲观的锁定.

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

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

乐观锁定解决方案

--  首先我们在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

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

上边我详细介绍了乐观锁定和悲观锁定的使用方法,在实际生产环境里边,如果并发量不大,我们完全可以使用悲观锁定的方法,因为这种方法使用起来非常方便和简单.但是如果系统的并发非常大的话,悲观锁定会带来非常大的性能问题,所以我们就要选择乐观锁定的方法.

如果大家发现文章里边有什么错误的地方,请及时提醒我,也欢迎有兴趣的一起研究讨论.

 

 
分享到:
评论

相关推荐

    SQL server 中锁机制详解

    SQL Server 中采用悲观锁还是乐观锁,取决于: 1:对用户实施不正确数据的可能性; 2:事务回滚的可能性; 3:事务自身的长度。 ANSI 定义了 4 种不同的隔离级别: 读提交(READCOMMITTED):SQL Server 缺省行为...

    Visual C++ +SQL Server数据库应用实例完全解析 4~5章

    5. **并发控制策略**:如乐观锁和悲观锁,以及SQL Server的锁定机制,如何在C++中实现这些策略。 6. **索引和查询优化**:提高数据库性能的关键,包括正确使用索引,优化SQL查询,以及避免全表扫描。 通过这两章的...

    SQL专家回答

    通过调整锁策略,例如使用乐观锁定或悲观锁定,可以优化并发性能。 - **事务隔离级别**:通过设置不同的事务隔离级别(如读已提交、可重复读、序列化等),可以平衡并发性和数据一致性。 - **死锁检测和预防**:SQL ...

    SQL concurrent programming

    在SQL Server中,有多种策略来处理并发问题,其中最常见的是锁定和行版本控制。 锁定是防止并发冲突的一种方法,也称为悲观并发控制。它在用户读取或修改数据时立即获取锁,阻止其他用户在同一时刻进行修改。锁定...

    SQL数据库SQL数据库SQL数据库

    9. **并发控制**:在多用户环境下,SQL数据库通过锁定机制、乐观锁或悲观锁等方式处理并发操作,防止数据冲突。 10. **安全性**:SQL数据库提供用户权限管理,可以设定不同用户对数据的不同访问级别,确保数据安全...

    sql学习笔记 常见问题总结

    2. 并发控制:并发操作可能导致数据不一致,通过锁定机制(如读锁、写锁)和乐观锁、悲观锁策略来解决。 六、索引优化 1. 索引:加速查询的关键工具,分为B树索引、哈希索引和全文索引等类型。创建索引可以提升...

    21天学会Sql

    同时,会涉及并发控制,如锁定机制和乐观锁、悲观锁的概念。 9. **性能优化**:讲解如何通过索引优化查询速度,避免全表扫描,以及调整查询语句和数据库设计以提高整体性能。 在学习过程中,读者可以参考`SQL21...

    SQL完全手册

    书中会介绍事务的ACID属性(原子性、一致性、隔离性和持久性),以及锁定机制、死锁处理和乐观锁/悲观锁的概念。 7. **SQL优化**:为了提升查询性能,书中会探讨索引的原理和使用、查询计划的分析以及性能调优的...

    使用TimeStamp控制并发问题示例

    例如死锁(Deadlock)或者第一读者写者问题(First-Come, First-Served Writer Problem),对于这些情况可能需要使用其他并发控制策略,如乐观锁定(Optimistic Locking)、悲观锁定(Pessimistic Locking)或者行...

    asp数据库课件(使用记录集对象)

    - `LockType`属性:定义锁定策略,如`adLockReadOnly`(只读)、`adLockPessimistic`(悲观锁定)、`adLockOptimistic`(乐观锁定)和`adLockBatchOptimistic`(批处理乐观锁定)。 3. Recordset的游标和锁定类型...

    数据库十二个例子

    乐观锁和悲观锁是两种主要的并发控制策略,分别在冲突发生时才进行检查和一开始就对资源进行锁定。 8. **安全性**:数据库安全涉及到用户权限管理、角色、访问控制列表(ACLs)和审计。通过设置用户认证、授权和...

    LINQ to SQL语句(13)之开放式并发控制和事务

    其中,LINQ to SQL是针对关系数据库的特定实现,它允许开发人员使用C#或VB.NET语言直接操作SQL Server数据库。本篇将深入探讨LINQ to SQL中的开放式并发控制和事务管理,这是数据库应用开发中至关重要的两个概念。 ...

    08_mt_l2s_concurrency

    LINQ(Language Integrated Query,语言集成查询)是.NET Framework中的一项技术,它允许开发者使用C#或Visual Basic.NET等语言的语法来查询各种数据源,而LINQ to SQL是针对SQL Server的一个特定实现,允许直接对...

    第14章 数据库及其相关技术

    乐观锁和悲观锁是两种主要的并发控制策略,前者假设冲突很少发生,而后者则在读取数据时进行锁定。此外,还有MVCC(多版本并发控制)机制,如在PostgreSQL中使用,允许并发读写操作而不直接锁定数据。 索引是提高...

    数据库系统原理

    乐观锁和悲观锁是两种常见的策略,前者假设冲突较少,在更新时检查是否有冲突;后者在读取数据时就锁定,防止其他用户修改。 备份与恢复是数据库系统的另一重要方面,以防数据丢失或损坏。定期备份可以保护数据,而...

    数据库原理及应用(特详细)(有数据库样例)(新手学习使用)

    了解锁定机制、乐观锁、悲观锁和多版本并发控制(MVCC)对于高并发应用至关重要。 9. **数据库性能优化**:包括索引的使用、查询优化、存储过程和视图的运用,以及数据库的参数调整。掌握这些技巧能提升数据库的...

    桌面\数据库原理及开发电子教案

    死锁、锁定机制和乐观/悲观并发策略是并发控制的关键概念。 7. **安全性与备份恢复**:数据库的安全性包括用户权限管理、数据加密和审计日志等,而备份恢复策略确保了在系统故障后能恢复数据。 8. **PowerBuilder*...

Global site tag (gtag.js) - Google Analytics