数据库锁机制

锁的类别有两种分法

SQL Server中锁模式

  1. 共享锁
    • 共享 (S) 锁允许并发事务读取 (SELECT) 一个资源。
    • 资源上存在共享 (S) 锁时,任何其它事务都不能修改数据。
    • 一旦已经读取数据,便立即释放资源上的共享 (S) 锁,除非将事务隔离级别设置为可重复读或更高级别,或者在事务生存周期内用锁定提示保留共享 (S) 锁。
  2. 更新锁
    • 更新 (U) 锁可以防止通常形式的死锁。
    • 一般更新模式由一个事务组成,此事务读取记录,获取资源(页或行)的共享 (S) 锁,然后修改行,此操作要求锁转换为排它 (X) 锁。如果两个事务获得了资源上的共享模式锁,然后试图同时更新数据,则一个事务尝试将锁转换为排它 (X) 锁。共享模式到排它锁的转换必须等待一段时间,因为一个事务的排它锁与其它事务的共享模式锁不兼容;发生锁等待。第二个事务试图获取排它 (X) 锁以进行更新。由于两个事务都要转换为排它 (X) 锁,并且每个事务都等待另一个事务释放共享模式锁,因此发生死锁。
    • 若要避免这种潜在的死锁问题,请使用更新 (U) 锁。一次只有一个事务可以获得资源的更新 (U) 锁。如果事务修改资源,则更新 (U) 锁转换为排它 (X) 锁。否则,锁转换为共享锁。
  3. 排它锁
    • 排它 (X) 锁可以防止并发事务对资源进行访问。其它事务不能读取或修改排它 (X) 锁锁定的数据
  4. 意向锁
    • 意向锁表示 SQL Server 需要在层次结构中的某些底层资源上获取共享 (S) 锁或排它 (X) 锁。例如,放置在表级的共享意向锁表示事务打算在表中的页或行上放置共享 (S) 锁。
    • 在表级设置意向锁可防止另一个事务随后在包含那一页的表上获取排它 (X) 锁。意向锁可以提高性能,因为 SQL Server 仅在表级检查意向锁来确定事务是否可以安全地获取该表上的锁。而无须检查表中的每行或每页上的锁以确定事务是否可以锁定整个表。
    • 意向锁包括意向共享 (IS)、意向排它 (IX) 以及与意向排它共享 (SIX)。
      1. 意向共享 (IS) 通过在各资源上放置 S 锁,表明事务的意向是读取层次结构中的部分(而不是全部)底层资源。
      2. 意向排它 (IX) 通过在各资源上放置 X 锁,表明事务的意向是修改层次结构中的部分(而不是全部)底层资源。IX 是 IS 的超集。
      3. 与意向排它共享 (SIX) 通过在各资源上放置 IX 锁,表明事务的意向是读取层次结构中的全部底层资源并修改部分(而不是全部)底层资源。允许顶层资源上的并发 IS 锁。例如,表的 SIX 锁在表上放置一个 SIX 锁(允许并发 IS 锁),在当前所修改页上放置 IX 锁(在已修改行上放置 X 锁)。虽然每个资源在一段时间内只能有一个 SIX 锁,以防止其它事务对资源进行更新,但是其它事务可以通过获取表级的 IS 锁来读取层次结构中的底层资源。

乐观锁和悲观锁

悲观锁
  • 悲观锁是基于一种悲观的态度类来防止一切数据冲突,它是以一种预防的姿态在修改数据之前把数据锁住,然后再对数据进行读写,在它释放锁之前任何人都不能对其数据进行操作,直到前面一个人把锁释放后下一个人数据加锁才可对数据进行加锁,然后才可以对数据进行操作,一般数据库本身锁的机制都是基于悲观锁的机制实现的;
  • 特点:可以完全保证数据的独占性和正确性,因为每次请求都会先对数据进行加锁, 然后进行数据操作,最后再解锁,而加锁释放锁的过程会造成消耗,所以性能不高;

在这里插入图片描述

乐观锁
  • 乐观锁是对于数据冲突保持一种乐观态度,操作数据时不会对操作的数据进行加锁(这使得多个任务可以并行的对数据进行操作),只有到数据提交的时候才通过一种机制来验证数据是否存在冲突(一般实现方式是通过加版本号然后进行版本号的对比方式实现);

  • 特点:乐观锁是一种并发类型的锁,其本身不对数据进行加锁通而是通过业务实现锁的功能,不对数据进行加锁就意味着允许多个请求同时访问数据,同时也省掉了对数据加锁和解锁的过程,这种方式因为节省了悲观锁加锁的操作,所以可以一定程度的的提高操作的性能,不过在并发非常高的情况下,会导致大量的请求冲突,冲突导致大部分操作无功而返而浪费资源,所以在高并发的场景下,乐观锁的性能却反而不如悲观锁。

在这里插入图片描述

锁的粒度
表级锁
  • 直接锁定整张表,在锁定期间,其他进程无法对该表进行写操作。如果写锁,则其他进程则读也不允许。
  • 特点:开销小、加锁快,不会出现死锁;锁定粒度最大,发生锁冲突的概率最高,并发度较低;更适合查询
  • MyISAM存储引擎采用的是表级锁。
  • 在 select 的时候自动加读锁,在 update delete insert时,自动加写锁。
  • 加锁命令:lock table 表名 read(一般不需要用户实现)
  • 去掉锁命令:unlock tables
  • 支持并发插入:支持查询和插入操作并发进行(在表尾并发插入)
  • 所调度机制:写锁优先。一个进程请求某个 MyISAM 表的读锁,同时另一个进程也请求同一表的写锁,MySQL 如何处理呢?写进程先获得锁,所以MyISAM不适合大量更新,因为大量更新会导致查操作很难获得读锁。
行锁级
  • 仅对指定的记录进行加锁,这样其他进程还是可以对同一个表中的其他记录进行操作。

  • 特点:开销大、加锁慢,会出现死锁。锁定粒度最小,发生冲突的概率最低,并发度也最高;更适合于有大量按索引条件,并发更新少量不同数据。

  • InnoDB 存储引擎既支持行级锁,也支持表级锁,但默认情况下是采用行级锁。

  • 意向锁是 InnoDB 自动加的,对于 update insert delete 会自动加排它锁,对于 select 不会自动加锁。

  • select * from user lock in share mode; 手动添加共享锁

  • select * from user for update; 手动添加排它锁

  • 行锁使用方式:

    1. 通过索引条件检索数据时,才使用行锁,否则用表锁;也就是如果select的where列不是索引列,那么此时,实际上是给整个表加锁。
    2. 检索条件是索引时,又分是聚集索引还是非聚集索引,如果是聚集索引(叶节点存放的整条记录),在聚集索引上的加上行锁;如果是非聚集索引,即要在非聚集索引记录上加行锁,又要在聚集索引上加行锁。
  • InnoDB 发生死锁的情况

    发生死锁后,InnoDB一般都能自动检测到,并使一个事务释放锁并回退,另一个事务得锁,继续完成事务。

页级锁
  • 一次锁定**相邻的一组记录。**开销和加锁时间界于表锁和行锁之间。

  • 特点:会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般。

  • 最常用的处理多用户并发访问的方法是加锁。当一个用户锁住数据库中的某个对象时,其他用户就不能再访问该对象。加锁对并发访问的影响体现在锁的粒度上。比如,表锁放在一个表上的锁限制对整个表的并发访问;页锁放在数据页上的锁限制了对整个数据页的访问;行锁放在行上的锁只限制对该行的并发访问。

  • 加锁处理

    • begin;

    • insert into test … 加insert对应的锁

    • update test set… 加update对应的锁

    • delete from test … 加delete对应的锁

    • commit;事务提交时,同时释放insert、update、delete对应的锁

  • 避免死锁

    • 在应用中,如果不同程序并发取多个表,应尽量约定以相同的顺序来访问数据库表。

    • 在程序以批量方式处理数据时,如果事先对数据排序,保证每个线程按固定的顺序来处理记录。

    • 在事务中,如果要更新记录,应该直接申请足够级别的锁,即排它锁;而不应先申请共享锁,更新时再申请排它锁。因为当用户申请排他锁时,其他事务可能又已经获得了相同记录的共享锁,从而造成死锁。

    • 在 Repeatable read(可重复读)隔离级别下,如果两个线程同时对相同条件记录用 select … for update 加排它锁,在没有符合记录情况下,两个线程都会加锁成功。程序发现记录尚不存在,就试图插入一条新的记录,如果两个线程都这么做,就会出现死锁。

    • 当隔离级别为 Read committed (读已提交)时,如果两个线程都先执行 select … for update,判断是否存在符合条件的记录,如果没有,就插入记录。此时,只有一个线程能插入成功,另一个线程会出现锁等待,当第1个线程提交后,第2个线程会因主键重合出错,但虽然这个线程出错了,却会获得一个排它锁,这时如果有第3个线程又来申请排它锁,也会造成死锁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值