锁
从锁的粒度,我们可以分成两大类:
-
表锁
-
开销小,加锁快;不会出现死锁;锁定力度大,发生锁冲突概率高,并发度最低
-
-
行锁
-
开销大,加锁慢;会出现死锁;锁定粒度小,发生锁冲突的概率低,并发度高
-
表锁
表锁下又分为两种模式:
-
表读锁(Table Read Lock)
-
表写锁(Table Write Lock)
-
从下图可以清晰看到,在表读锁和表写锁的环境下:读读不阻塞,读写阻塞,写写阻塞!
-
读读不阻塞:当前用户在读数据,其他的用户也在读数据,不会加锁
-
读写阻塞:当前用户在读数据,其他的用户不能修改当前用户读的数据,会加锁!
-
写写阻塞:当前用户在修改数据,其他的用户不能修改当前用户正在修改的数据,会加锁!
-
读锁和写锁是互斥的,读写操作是串行。
-
如果某个进程想要获取读锁,同时另外一个进程想要获取写锁。在mysql里边,写锁是优先于读锁的!
-
写锁和读锁优先级的问题是可以通过参数调节的:
max_write_lock_count
和low-priority-updates
行锁
两种类型的行锁。
-
共享锁(S锁):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。
-
也叫做读锁:读锁是共享的,多个客户可以同时读取同一个资源,但不允许其他客户修改。
-
-
排他锁(X锁):允许获得排他锁的事务更新数据,阻止其他事务取得相同数据集的共享读锁和排他写锁。
-
也叫做写锁:写锁是排他的,写锁会阻塞其他的写锁和读锁
-
乐观锁和悲观锁
-
乐观锁是一种思想,具体实现是,表中有一个版本字段,第一次读的时候,获取到这个字段。处理完业务逻辑开始更新的时候,需要再次查看该字段的值是否和第一次的一样。如果一样更新,反之拒绝。之所以叫乐观,因为这个模式没有从数据库加锁,等到更新的时候再判断是否可以更新。
-
悲观锁是数据库层面加锁,都会阻塞去等待锁。
悲观锁
悲观锁的话其实很简单(手动加行锁就行了):
-
select * from xxxx for update
在select 语句后边加了 forupdate
相当于加了排它锁(写锁),加了写锁以后,其他的事务就不能对它修改了!需要等待当前事务修改完之后才可以修改.
当使用select … for update …where …时,mysql进行row lock还是table lock只取决于是否能使用索引(例如主键,unique字段),能则为行锁,否则为表锁;未查到数据则无锁。而 使用’<>’,'like’等操作时,索引会失效,自然进行的是table lock
乐观锁