索引和锁是数据库中的两个核心知识点,不论在工作中,还是在面试中,我们都会经常跟它们打交道。

加锁是为了保证数据的一致性,这个思想在程序开发领域中同样很重要。在程序开发 中也会存在多线程同步的问题。当多个线程并发访问某个数据的时候,尤其是针对一些敏感 的数据(比如订单、金额等),我们就需要保证这个数据在任何时刻多只有一个线程在进 行访问,保证数据的完整性和一致性。


按锁的粒度划分

分为行锁、页锁、表锁

行锁就是按照行的粒度对数据进行锁定。锁定力度小,发生锁冲突概率低,可以实现的并发度高,但是对于锁的开销比较大,加锁会比较慢,容易出现死锁情况

页锁就是在页的粒度上进行锁定,锁定的数据资源比行锁要多,因为一个页中可以有多个行 记录。当我们使用页锁的时候,会出现数据浪费的现象,但这样的浪费多也就是一个页上的数据行。页锁的开销介于表锁和行锁之间,会出现死锁。锁定粒度介于表锁和行锁之间, 并发度一般。

表锁就是对数据表进行锁定,锁定粒度很大,同时发生锁冲突的概率也会较高,数据访问的并发度低。不过好处在于对锁的使用开销小,加锁会很快。


从数据库管理的角度对锁进行划分

共享锁

共享锁也叫读锁或 S 锁,共享锁锁定的资源可以被其他用户读取,但不能修改。在进行SELECT的时候,会将对象进行共享锁锁定,当数据读取完毕之后,就会释放共享锁,这样就可以保证数据在读取时不被修改。

比如给tin_componentlibrary在表上加共享锁,可以使用下面这行命令:

更改数据就会显示下图所示的内容,也就是当共享锁没有释放时,不能对锁住的数据进行修改。

解锁

如果我们想要给某一行加上共享锁呢,比如想对 componentId=0445946 的数据行加上共享锁,可以像下面这样:

排他锁

排它锁也叫独占锁、写锁或 X 锁。排它锁锁定的数据只允许进行锁定操作的事务使用,其他事务无法对已锁定的数据进行查询或修改。

如果我们想给 tin_componentlibrary数据表添加排它锁,可以使用下面这行命令:

这时只有获得排它锁的事务可以对 tin_componentlibrary进行查询或修改,其他事务如果想要在 product_comment 表上查询数据,则需要等待

释放掉排它锁

同样的,如果我们想要在某个数据行上添加排它锁,比如针对 componentId=0445946的数据行,则写成如下这样:

另外当我们对数据进行更新的时候,也就是INSERT、DELETE或者UPDATE的时候,数据库也会自动使用排它锁,防止其他事务对该数据行进行操作

当我们想要获取某个数据表的排它锁的时候,需要先看下这张数据表有没有上了排它锁。如 果这个数据表中的某个数据行被上了行锁,我们就无法获取排它锁。这时需要对数据表中的 行逐一排查,检查是否有行锁,如果没有,才可以获取这张数据表的排它锁。这个过程是不 是有些麻烦?这里就需要用到意向锁

意向锁

简单来说就是给更大一级别的空间示意里面是否已经上过锁。举个例子,你可以给整个房子设置一个标识,告诉它里面有人,即使你只是获取了房子中某一 个房间的锁。这样其他人如果想要获取整个房子的控制权,只需要看这个房子的标识即可, 不需要再对房子中的每个房间进行查找。这样是不是很方便?

返回数据表的场景,如果我们给某一行数据加上了排它锁,数据库会自动给更大一级的空 间,比如数据页或数据表加上意向锁,告诉其他人这个数据页或数据表已经有人上过排它锁 了,这样当其他人想要获取数据表排它锁的时候,只需要了解是否有人已经获取了这个数据 表的意向排他锁即可

如果事务想要获得数据表中某些记录的共享锁,就需要在数据表上添加意向共享锁。同理,事务想要获得数据表中某些记录的排他锁,就需要在数据表上添加意向排他锁。这时,意向锁会告诉其他事务已经有人锁定了表中的某些记录,不能对整个表进行全表扫描。


程序员角度进行划分

乐观锁

认为对同一数据的并发操作不会总发生,属于小概率事件, 不用每次都对数据上锁,也就是不采用数据库自身的锁机制,而是通过程序来实现。在程序上,我们可以采用版本号机制或者时间戳机制实现。

版本号机制

在表中设计一个版本字段 version,第一次读的时候,会获取 version 字段的取值。然后对 数据进行更新或删除操作时,会执行UPDATE ... SET version=version+1 WHERE version=version。此时如果已经有事务对这条数据进行了更改,修改就不会成功

时间戳机制

时间戳和版本号机制一样,也是在更新提交的时候,将当前数据的时间戳和更新之前取得的 时间戳进行比较,如果两者一致则更新成功,否则就是版本冲突。

悲观锁

对数据被其他事务的修改持保守态度,会 通过数据库自身的锁机制来实现,从而保证数据操作的排它性。

乐观锁和悲观锁的适用场景:

乐观锁适合读操作多的场景,相对来说写的操作比较少。它的优点在于程序实现,不存在死锁问题,不过适用场景也会相对乐观,因为它阻止不了除了程序以外的数据库操作。

悲观锁适合写操作多的场景,因为写的操作具有排它性。采用悲观锁的方式,可以在数据库层面阻止其他事务对该数据的操作权限,防止读 - 写和写 - 写的冲突

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值