锁是多用户访问同一数据库资源时,对访问的先后次序权限管理的机制

分类

锁思想

  • 悲观锁: 每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会 block 直到它拿到锁
    • 假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作
  • 乐观锁: 每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在提交更新时会判断在此期间别人有没有去更新这个数据
    • 假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性
    • 乐观锁适用于读多写少的应用场景,这样可以提高吞吐量
    • 使用 时间戳(timestamp)和 数据版本(Version)记录机制实现

      乐观锁和悲观锁并不是锁,而是锁的设计思想

锁模式

  • 共享锁: 也叫读锁 或 S锁,锁定的资源可以被其它用户读取,但其它用户不能修改它

    • 在 SELECT 命令执行时,SQL Server 通常会对对象进行共享锁锁定
    • 通常共享锁的数据页被读取完毕后,共享锁就会立即被释放,这样就可以保证数据在读取时不被修改
  • 独占锁: 也叫写锁 或 X锁,锁定的资源只允许进行锁定操作的事务使用,其他事务无法对已锁定的数据进行查询或修改

    • 执行数据更新命令,即 INSERT、 UPDATE 或DELETE 命令时,SQL Server 会自动使用独占锁
    • 当对象上有其它锁存在时,无法对其加独占锁
    • 独占锁一直到事务结束才能被释放
  • 更新锁: 为了防止死锁而设立的

    • 当 SQL Server 准备更新数据时,它首先对数据对象作更新锁锁定,这样数据将不能被修改,但可以读取
    • 等到 SQL Server 确定要进行更新数据操作时,它会自动将更新锁换为独占锁
    • 但当对象上有其它锁存在时,无法对其作更新锁锁定

锁类型

  • ⾏锁:SQL Server中数据级别中粒度最⼩的锁级别,⾏锁根据表是否存在聚集索引,分为键值锁和标识锁
  • 页锁:针对某个数据页添加的锁,在T-SQL语句中,使⽤了页锁就不会在使⽤相同类型的⾏锁,反之依然,在对数据页加锁后,⽆法在对其添加不兼容的锁
  • 表锁:添加表锁则⽆法添加与其不兼容的页

实例

行锁( ROWLOCK )

  1. SELECT * FROM 表名 ROWLOCK WHERE子句;

行级锁确保在用户取得被更新的行,到该行进行更新,这段时间内不被其它用户所修改。因而行级锁即可保证数据的一致性,又能提高数据操作的并发性

表锁 ( TABLELOCKX )

  1. SELECT * FROM 表名 TABLELOCKX WHERE子句;

共享锁( HOLDLOCK )

  1. SELECT * FROM 表名 WITH(HOLDLOCK) WHERE子句;

更新锁( UPLOAD )

  1. UPDATE 表名 WITH(UPLOAD) SET 列名 WHERE子句;

更新数据时,会将更新锁自动转换为排它锁

死锁

事务与锁

  • 事务具有ACID特征,锁是用于解决隔离性的一种机制
  • 事务的隔离级别通过锁的机制来实现
  • 锁有不同的粒度,事务也是有不同的隔离级别的