事务和锁机制是啥关系? 开启事务就自动加锁了吗? 菜鸟,谢谢了。
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了事务和锁机制是啥关系? 开启事务就自动加锁了吗? 菜鸟,谢谢了。相关的知识,希望对你有一定的参考价值。
1、事务与锁是不同的。事务具有ACID(原子性、一致性、隔离性和持久性),锁是用于解决隔离性的一种机制。
2、事务的隔离级别通过锁的机制来实现。另外锁有不同的粒度,同时事务也是有不同的隔离级别的。
3、开启事务就自动加锁。
ql规范定义的事务的隔离级别:
1.READ UNCOMMITTED(读取未提交内容)
所有事务可以看到未提交事务的执行结果,本隔离级别很少用到实际应用中,读取未提交的数据,又称为“脏读”。
2.READ COMMITTED(读取提交内容)
大多数数据库的默认隔离级别是此级别,但不是mysql默认的。一个事务在开始的时候只能看见已提交事务所做的改变。一个事务从开始到提交前所做的任何改变都是不可见的,除非提交。这种隔离级别也称为不可重复读。
3.REPEATABLE READ(可重复读)
此隔离级别是为了解决可重复读隔离级别导致的问题即一个事务多个实例并发读取数据时会看到不同的结果。此隔离级别不会看到其他事务提交后的结果,即事务即使提交了我也看不到。此级别也称为“幻读”。
4.SERIALIZABLE(可串行化)
可串行化是最高的隔离级别,它通过强制事务排序,使之不可重读,解决了幻读的问题。此隔离级别会在每个读的数据行上加共享锁,使用这种隔离级别会产生大量的超时现象,一般实际开发中不会用到。
mysql加锁机制:
根据类型可分为共享锁(SHARED LOCK)和排他锁(EXCLUSIVE LOCK)或者叫读锁(READ LOCK)和写锁(WRITE LOCK)。
根据粒度划分又分表锁和行锁。表锁由数据库服务器实现,行锁由存储引擎实现。
mysql提供了3种事务型存储引擎,InnDB、NDB Cluster和Falcon。
一个事务执行的任何过程中都可以获得锁,但是只有事务提交或回滚的时候才释放这些锁。这些都是隐式锁定,也可以显式锁定,InnoDB支持显式锁定,例如:
SELECT .... LOCK IN SHARE MODE (加共享锁)
SELECT .....FOR UPDATE(加排他锁)
多版本并发控制(重要):
Mysql的事务存储引擎不是简单实用行加锁机制,而是叫多版本并发控制(MVCC)技术,和行加锁机制关联实用。以便应对更高的并发,当然是以消耗性能作为代价。
每种存储引擎对MVCC的实现方式不同,InnoDB引擎的简单实现方式如下:
InnoDB通过为每个数据航增加两个隐含值的方式来实现。这两个隐含值记录了行的创建时间,以及过期时间。每一行存储事件发生时的系统版本号。每一次开始一个新事务时版本号会自动加1,每个事务都会保存开始时的版本号,每个查询根据事务的版本号来查询结果。
MySQL使用以下几种机制进行隔离性的实现: a.锁机制 通过使用加锁机制,使用其它事务无法到读某事务末提交前的数据更新,解决脏读问题; mySQL 有:共享锁,排他锁,根据粒度,有行锁,表锁。 b.MVCC机制: 事务存储引擎使用多版本并发控制(MVCC)技术,和行加锁机制关联使用 MySQL 的InnoDB,XtraDB 引擎通过 使用MVCC 来解决幻读问题。
参考技术A 事务与锁是不同的。事务具有ACID(原子性、一致性、隔离性和持久性),锁是用于解决隔离性的一种机制。事务的隔离级别通过锁的机制来实现。另外锁有不同的粒度,同时事务也是有不同的隔离级别的(一般有四种:读未提交Read uncommitted,读已提交Read committed,可重复读Repeatable read,可串行化Serializable)。在具体的程序设计中,开启事务其实是要数据库支持才行的,如果数据库本身不支持事务,那么仍然无法确保你在程序中使用的事务是有效的。锁可以分为乐观锁和悲观锁:悲观锁:认为在修改数据库数据的这段时间里存在着也想修改此数据的事务;乐观锁:认为在短暂的时间里不会有事务来修改此数据库的数据;我们一般意义上讲的锁其实是指悲观锁,在数据处理过程中,将数据置于锁定状态(由数据库实现)。回到你的问题,如果开启了事务,在事务没提交之前,别人是无法修改该数据的;如果rollback,你在本次事务中的修改将撤消(不是别人修改的会没有,因为别人此时无法修改)。当然,前提是你使用的数据库支持事务。还有一个要注意的是,部分数据库支持自定义SQL锁覆盖事务隔离级别默认的锁机制,如果使用了自定义的锁,那就另当别论。重点:一般事务使用的是悲观锁(具有排他性)。本回答被提问者采纳RDB | MySQL的事务隔离级别和锁的机制
对于后端开发面试,关系型数据库是一个必问考点。而在目前主流的关系型数据库中,MySQL无疑是互联网圈中最火热的一个。掌握MySQL的核心知识点,对于面试取得一个好成绩很重要!
我们都知道目前MySQL的事务隔离级别主要有四个,分别是:读未提交、读已提交、可重复读 和 串行化,如下图所示:
按隔离水平高低排序:读未提交<读已提交<可重复读<串行化。
(1)读未提交:读未提交:隔离级别最低,隔离度最弱,理论存在,实际中几乎没有人用,但性能最高。该级别存在的问题包括 脏读、不可重复读 和 幻读。
(2)读已提交:保证了事务不出现中间状态的数据,所有数据都是已提交且更新的。该级别存在的问题有 不可重复读 和 幻读。
(3)可重复读:MySQL InnoDB引擎的默认隔离级别,保证了一个事务中多次读取数据的一致性。该级别存在的问题有 幻读,但它是MySQL的默认事务隔离级别。
(4)可串行化:读数据需要加共享锁,写数据需要加排它锁,安全性最高,性能最低,但该级别解决了幻读的问题。
悲观锁与乐观锁
在关系型数据库中,按使用方式来说,有两种典型的锁,分别是 悲观锁 与 乐观锁。
悲观锁认为认为数据出现冲突的可能性很大,例子:SELECT ... FOR UPDATE。
乐观锁认为数据出现冲突的可能性不大,例子:对比数据行的时间戳或版本号。
表级锁和行级锁
在关系型数据库中,按粒度来划分的话,有三种类型的锁,分别是 表级锁、行级锁 和 页级锁。我们常用的锁有行级锁和表级锁。
MySQL中表级锁有两类:一是表锁,二是元数据锁。表锁的语法为:lock tables ... read/write。它限制了别的线程,也限定了本线程接下来的操作对象。
表锁一般是在数据库引擎不支持行锁的时候才会被用到,比如MyISAM引擎。
MySQL 5.5引入了MDL(元数据锁),不需要显示使用,在访问一个表的时候会自动被加上。
当对一个表做增删改查时,自动加MDL读锁(读锁之间不互斥);
当对一个表做表结构变更时,自动加MDL写锁(读写锁与写锁之间互斥);
MDL的作用:保证读写的正确性。
MDL带来的问题:修改表结构时申请MDL写锁,可能会导致锁表,后续业务操作均会阻塞。
在MySQL中,行锁是引擎层由各个引擎自己实现的,但并不是所有引擎都支持行锁例如MyISAM就不支持,所以我们默认会使用InnoDB引擎。
所谓行锁,就是针对数据表中行记录的锁。比如,事务A更新了一行,这时事务B也要更新同一行,那么事务B需要等待事务A的操作完成后才能进行。
更多关于表锁和行锁的内容请阅读《》。
脏读
所谓脏读,就是指 读到了未提交事务的数据。
脏读对应的隔离级别是“读未提交”,只有该隔离级别才会出现脏读。
脏读的解决办法是升级事务隔离级别,比如“读已提交”。
不可重复读
所谓不可重复读,就是两次读取的数据中途被修改。
不可重复读对应的隔离级别是“读未提交”或“读已提交”。
不可重复读的解决办法就是升级事务隔离级别,比如“可重复读”。
幻读
所谓幻读,是指在同一个事务内,同一条查询语句在不同的时间段执行会得到不同的结果集。
要解决幻读不能简单升级事务隔离级别到可串行化,因为会让MySQL失去并发处理能力。
行锁解决不了幻读,因为即使锁住所有记录,还是阻止不了插入新数据。
解决幻读的办法是锁住记录之间的“间隙”,为此InnoDB引入了新的间隙锁 (Gap Lock) 和next-key lock锁。
顾名思义,间隙锁,锁的就是两个值之间的空隙。
比如下图所示的某张表t,在该表主键索引(id)上插入了6个记录(0,5,10,15,20,25),因此产生了7个间隙。
CREATE TABLE `t` (
`id` int(11) NOT NULL,
`c` int(11) DEFAULT NULL,
`d` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `c` (`c`)
) ENGINE=InnoDB;
insert into t values(0,0,0),(5,5,5),
(10,10,10),(15,15,15),(20,20,20),(25,25,25);
图片来源:林晓斌《MySQL实战45讲》
间隙锁是专门用于解决幻读这种问题的锁,它锁了行与行之间的间隙,这样就能够阻塞新插入的操作。
因此,划重点:当MySQL InnoDB引擎在一行行扫描的过程中,不仅会给行加上行锁,还会给行的两边的空隙也加上间隙锁。
由于间隙锁(gap lock)仍在存在一些问题,可能会降低并发度和仍然可能导致死锁。因此,MySQL InnoDB为间隙锁引入了一个补充:next-key lock。
那么,问题来了:啥是next-key lock?
所谓next-key lock,它是间隙锁和行锁的合体,每个next-key lock都是前开后闭区间,如 (0,5]。
间隙锁都是开区间,如 (0,5)。
next-key lock帮助MySQL在默认隔离级别下解决了幻读问题,因此它也是MySQL加锁的基本单位。
更多关于间隙锁和next-key lock的介绍请阅读《》
死锁是如何产生的?
死锁一般发生在多线程(两个或两个以上)执行的过程中,因为争夺资源造成线程之间相互等待。
死锁的产生需要具备4个条件:
(1)互斥:多个线程不能同时使用一个资源;
(2)持有并等待:在已经持有了资源1的情形下又申请资源2,但是资源2已经被其他事务占用;
(3)不可剥夺:在事务已经获取到资源1之后,在使用完之前都不可以被其他事务抢占;
(4)循环等待:发生死锁时,必然会存在一个事务,也就是资源的环形链;
如何避免死锁发生?
对于死锁,我们需要有一个基本认知:死锁只有同时满足四个条件时才会发生,并发场景下一旦发生死锁,并没有什么特别好的办法,最好是规避死锁。
因此,要避免死锁,我们需要至少破坏四个条件中的一个(互斥必须满足,可以从其他三个条件出发)。
(1)破解持有并等待:我们可以一次性申请所有的资源;
(2)破解不可剥夺:如果申请不到资源,可以主动释放占有的资源;
(3)破解循环等待:按序申请资源来预防(即资源有序分配原则);
本文总结了MySQL的事务隔离级别和锁的机制相关的知识点,希望能对你有所帮助!不过,本文只是高层概览,更详细的细节还是需要你参考更多扩展资料才能应对面试的需求。下一篇,我们会聚焦MySQL如何优化数据查询的方案,即在读多写少的场景下如何优化查询性能。
参考资料
丁奇,《MySQL实战45讲》(极客时间)
刘海丰,《架构设计面试精讲》(拉勾教育)
施瓦茨,《高性能MySQL(第三版)》(图书)
狼爷,《》(博客园)
以上是关于事务和锁机制是啥关系? 开启事务就自动加锁了吗? 菜鸟,谢谢了。的主要内容,如果未能解决你的问题,请参考以下文章