【MySQL】——MySQL中的锁机制

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/fjj15732621696/article/details/82724873

概述

相对其他数据库来说,MySQL的锁机制比较简单,不同的存储引擎支持不同的锁机制。
MySQL大致可以分为以下3种锁

  • 表级锁:操作对象是数据表。MySQL大多数锁策略都支持,开销小,加锁快。不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发度最低。
  • 行级锁:操作对象是数据表中的一行,开销大,加锁慢;会出现死锁;锁定粒度最小,发生所冲突的概率最低,并发度也最高。
  • 页面锁:开销和加锁时间界定于表锁和行锁之间;会出现死锁;锁定粒度介于表锁和行锁之间,并发度一般。

MyISAM表锁

MySQL的表锁有两种模式:表共享读锁(Table Read Lock)和表独占写锁(Table Write Lock)。

表锁兼容模式
当前锁模式/是否兼容 None 读锁 写锁
读锁
写锁
  • 对MyISAM的读操作,不会阻塞其他用户对同一表的读请求,但是阻塞对同一表的写操作。

  • 对MyISAM的写操作,则会阻塞其他用户对同一表的读写操作。

  • MyISAM表的读操作和写操作,以及写操作之间都是串行的。

    并发插入

    MyISAM存储引擎有一个系统变量concurrent_insert,专门用以控制其并发插入的行为,其值分别可以为0、1或2。

  • 当concurrent_insert设置为0时,不允许并发插入。

  • 当concurrent_insert设置为1时,如果MyISAM表中没有空洞(即表的中间没有被删除的行),MyISAM允许在一个进程读表的同时,另一个进程从表尾插入记录。这也是MySQL的默认设置。

  • 当concurrent_insert设置为2时,无论MyISAM表中有没有空洞,都允许在表尾并发插入记录。

只需在加表锁命令中加入“local”选项,即:lock table tbl_name local read,在满足MyISAM表并发插入条件的情况下,其他用户就可以在表尾并发插入记录,但更新操作会被阻塞,而且加锁的用户无法访问到其他用户并发插入的记录。

MyISAM锁调度

当写进程和读进程同时请求同一个MyISAM表的写锁和读锁时,写进程会优先获得锁。不仅如此,即使读请求先到锁等待队列,写请求后到,写锁也会插到读锁请求之前!这是因为MySQL认为写请求一般比读请求更重要。这也正是MyISAM表不太适合于有大量更新操作和查询操作应用的原因,因为大量的更新操作会造成查询操作很难获得读锁,从而可能永远阻塞。
通过一下一些设置调节MyISAM的调度行为:

  • 通过指定启动参数low-priority-updates,使MyISAM引擎默认给予读请求以优先的权利。

  • 通过执行命令SET LOW_PRIORITY_UPDATES=1,使该连接发出的更新请求优先级降低。

  • 通过指定INSERT、UPDATE、DELETE语句的LOW_PRIORITY属性,降低该语句的优先级。

InnoDB锁问题

InnoDB与MyISAM的最大不同有两点:1、支持事务(TRANSACTION)2、采用了行级锁

事务(Transaction)及其ACID属性

事务是有一组SQL语句组成的逻辑处理单元,事务由4个属性通常我们也成为ACID属性。

  • 原子性(Atomicity):事务是一个原子操作,其对数据的修改,要么全部执行,要么全部不执行。

  • 一致性(Consistency):事务的一致性指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。如果事务成功地完成,那么系统中所有变化将正确地应用,系统处于有效状态。如果在事务中出现错误,那么系统中的所有变化将自动地回滚,系统返回到原始状态。

  • 隔离性(Isolation):隔离性指并发的事务是相互隔离的。即一个事务内部的操作及正在操作的数据必须封锁起来,不被其他企图进行修改的事务看到。

  • 持久性(Durability):是指一个事务一旦被提交,它对数据库中的数据的改变时永久性的,接下来的其他操作和数据库故障不应该对其有任何影响。即一旦一个事务提交。DBMS(Database Management System)保证它对数据库中数据的改变应该是永久性的,持久性通过数据库备份和恢复来保证。

并发事务带来的问题

相对于串行处理来说,并发事务处理能大大增加数据库资源的利用率,提高数据库系统的事务吞吐量,从而可以支持可以支持更多的用户。但并发事务处理也会带来一些问题,主要包括以下几种情况。

  • 更新丢失(Lost Update):当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题——最后的更新覆盖了其他事务所做的更新。例如,两个编辑人员制作了同一文档的电子副本。每个编辑人员独立地更改其副本,然后保存更改后的副本,这样就覆盖了原始文档。最后保存其更改保存其更改副本的编辑人员覆盖另一个编辑人员所做的修改。如果在一个编辑人员完成并提交事务之前,另一个编辑人员不能访问同一文件,则可避免此问题

  • 脏读(Dirty Reads):一个事务正在对一条记录做修改,在这个事务并提交前,这条记录的数据就处于不一致状态;这时,另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些“脏”的数据,并据此做进一步的处理,就会产生未提交的数据依赖关系。这种现象被形象地叫做“脏读”。

  • 不可重复读(Non-Repeatable Reads):一个事务在读取某些数据已经发生了改变、或某些记录已经被删除了!这种现象叫做“不可重复读”。

  • 幻读(Phantom Reads):一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读”。

事务的隔离级别

详见上篇博客

InnoDB的行锁模式及加锁方式

InnoDB实现了以下两种类型的行锁

  • 读锁:也加共享锁、S锁。若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S 锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。

  • 写锁:又称排他锁、X锁。若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。这保证了其他事务在T释放A上的锁之前不能再读取和修改A。

    另外,为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB还有两种内部使用的意向锁(Intention Locks),这两种意向锁都是表锁。

  • 意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。

  • 意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。

    锁机制

如果一个事务请求的锁模式与当前的锁模式兼容,InnoDB就将请求的锁授予该事务;反之,如果两者不兼容,该事务就要等待锁释放。
意向锁是InnoDB自动加的,不需要用户干预。对于update、delete、insert语句,InnoDB会自动给设计数据集加排它锁;对于普通select语句,InnoDB不会加任何锁;事务可以通过以下语句显示给记录集加共享锁或者排它锁

SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE  共享锁(S锁)
SELECT * FROM table_name WHERE ... FOR UPDATE    排它锁(X锁)

用Select….in share mode 获得共享锁,主要用在需要数据依赖关系是来确认某行记录是否存在,并确保没有人对这个记录进行update或delete操作。如果当前事务需要对该记录进行更新操作,则很有可能造成死锁,对于锁定行记录进行更新操作的应用,应该使用select ….for update 方式获得排它锁。

猜你喜欢

转载自blog.csdn.net/fjj15732621696/article/details/82724873