从锁的粒度,我们可以分成两大类:

  • 表锁

    • 开销小,加锁快;不会出现死锁;锁定力度大,发生锁冲突概率高,并发度最低

  • 行锁

    • 开销大,加锁慢;会出现死锁;锁定粒度小,发生锁冲突的概率低,并发度高

表锁

表锁下又分为两种模式

  • 表读锁(Table Read Lock)

  • 表写锁(Table Write Lock)

  • 从下图可以清晰看到,在表读锁和表写锁的环境下:读读不阻塞,读写阻塞,写写阻塞

    • 读读不阻塞:当前用户在读数据,其他的用户也在读数据,不会加锁

    • 读写阻塞:当前用户在读数据,其他的用户不能修改当前用户读的数据,会加锁!

    • 写写阻塞:当前用户在修改数据,其他的用户不能修改当前用户正在修改的数据,会加锁!

读锁和写锁是互斥的,读写操作是串行

  • 如果某个进程想要获取读锁,同时另外一个进程想要获取写锁。在mysql里边,写锁是优先于读锁的

  • 写锁和读锁优先级的问题是可以通过参数调节的: max_write_lock_countlow-priority-updates

行锁

两种类型的行锁。

  • 共享锁(S锁):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。

    • 也叫做读锁:读锁是共享的,多个客户可以同时读取同一个资源,但不允许其他客户修改

  • 排他锁(X锁):允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。

    • 也叫做写锁:写锁是排他的,写锁会阻塞其他的写锁和读锁

乐观锁和悲观锁

  1. 乐观锁是一种思想,具体实现是,表中有一个版本字段,第一次读的时候,获取到这个字段。处理完业务逻辑开始更新的时候,需要再次查看该字段的值是否和第一次的一样。如果一样更新,反之拒绝。之所以叫乐观,因为这个模式没有从数据库加锁,等到更新的时候再判断是否可以更新。

  2. 悲观锁是数据库层面加锁,都会阻塞去等待锁。

悲观锁

悲观锁的话其实很简单(手动加行锁就行了):

  • select * from xxxx for update

在select 语句后边加了 forupdate相当于加了排它锁(写锁),加了写锁以后,其他的事务就不能对它修改了!需要等待当前事务修改完之后才可以修改.

当使用select … for update …where …时,mysql进行row lock还是table lock只取决于是否能使用索引(例如主键,unique字段),能则为行锁,否则为表锁;未查到数据则无锁。而 使用’<>’,'like’等操作时,索引会失效,自然进行的是table lock

乐观锁

乐观锁不是数据库层面上的锁,是需要自己手动去加的锁。一般添加一个版本字段(version)来实现,每次更新数据都手动更新version,每次更新数据前都手动校验version

posted @ 2020-08-14 23:45  huiyii  阅读(97)  评论(0编辑  收藏  举报