锁是多用户访问同一数据库资源时,对访问的先后次序权限管理的机制
分类
锁思想
- 悲观锁: 每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会 block 直到它拿到锁
- 假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作
- 乐观锁: 每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在提交更新时会判断在此期间别人有没有去更新这个数据
- 假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性
- 乐观锁适用于读多写少的应用场景,这样可以提高吞吐量
- 使用 时间戳(timestamp)和 数据版本(Version)记录机制实现
乐观锁和悲观锁并不是锁,而是锁的设计思想
锁模式
共享锁: 也叫读锁 或 S锁,锁定的资源可以被其它用户读取,但其它用户不能修改它
- 在 SELECT 命令执行时,SQL Server 通常会对对象进行共享锁锁定
- 通常共享锁的数据页被读取完毕后,共享锁就会立即被释放,这样就可以保证数据在读取时不被修改
独占锁: 也叫写锁 或 X锁,锁定的资源只允许进行锁定操作的事务使用,其他事务无法对已锁定的数据进行查询或修改
- 执行数据更新命令,即 INSERT、 UPDATE 或DELETE 命令时,SQL Server 会自动使用独占锁
- 当对象上有其它锁存在时,无法对其加独占锁
- 独占锁一直到事务结束才能被释放
更新锁: 为了防止死锁而设立的
- 当 SQL Server 准备更新数据时,它首先对数据对象作更新锁锁定,这样数据将不能被修改,但可以读取
- 等到 SQL Server 确定要进行更新数据操作时,它会自动将更新锁换为独占锁
- 但当对象上有其它锁存在时,无法对其作更新锁锁定
锁类型
- ⾏锁:SQL Server中数据级别中粒度最⼩的锁级别,⾏锁根据表是否存在聚集索引,分为键值锁和标识锁
- 页锁:针对某个数据页添加的锁,在T-SQL语句中,使⽤了页锁就不会在使⽤相同类型的⾏锁,反之依然,在对数据页加锁后,⽆法在对其添加不兼容的锁
- 表锁:添加表锁则⽆法添加与其不兼容的页
实例
行锁( ROWLOCK )
SELECT * FROM 表名 ROWLOCK WHERE子句;
行级锁确保在用户取得被更新的行,到该行进行更新,这段时间内不被其它用户所修改。因而行级锁即可保证数据的一致性,又能提高数据操作的并发性
表锁 ( TABLELOCKX )
SELECT * FROM 表名 TABLELOCKX WHERE子句;
共享锁( HOLDLOCK )
SELECT * FROM 表名 WITH(HOLDLOCK) WHERE子句;
更新锁( UPLOAD )
UPDATE 表名 WITH(UPLOAD) SET 列名 WHERE子句;
更新数据时,会将更新锁自动转换为排它锁
死锁
事务与锁
- 事务具有ACID特征,锁是用于解决隔离性的一种机制
- 事务的隔离级别通过锁的机制来实现
- 锁有不同的粒度,事务也是有不同的隔离级别的
