前序
原文链接1:https://cloud.tencent.com/developer/article/1899373
原文链接2:https://zhuanlan.zhihu.com/p/53619907
原文链接3:https://zhuanlan.zhihu.com/p/117476959
什么是存储引擎?
存储引擎是数据库管理系统中用于存储、管理和检索数据的底层软件组件【也就是使用存储引擎可以创建、查询、更新、删除数据库】。它负责处理数据的物理存储和检索,以及支持数据库的事务处理、并发控制、数据完整性和安全性等功能。比如MySQL常见的存储引擎包括InnoDB、MyISAM、MongoDB等。不同的存储引擎具有不同的特性和适用场景,因此在选择存储引擎时需要根据具体的应用需求进行选择。
MySQL常用引擎
MySQL有9种存储引擎,不同的引擎,适合不同的场景,常用引擎为InnoDB,它是MySQL的默认存储引擎。
登录MySQL,执行show engines可以查询MySQL支持的存储引擎,如图示:
其中“YES”表示可以使用,“NO”表示不能使用,“DEFAULT”表示为当前数据库默认的存储引擎。
1、InnoDB引擎
(1)它事务型数据库的首选引擎,支持事务安全表(ACID),支持行锁定和外键。缺点以损失效率来保证数据的一致性。
(2)存储表和索引有两种形式:
A:使用共享表空间存储:所有的表和索引存放在同一个表空间中。
B:使用多表空间存储:表结构放在frm文件,数据和索引放在IBD文件中。分区表的每个分区对应单独的IBD文件,使用分区表的好处在于提升查询效率。
2、MyISAM引擎
没有事务,拥有较高的插入、查询速度,每个MyISAM在磁盘上存储成三个文件
(1)frm文件:存储表的定义数据
(2)MYD文件:存放表具体记录的数据。
(3)MYI文件:存储索引
3、MEMORY
MEMORY存储引擎将表中的数据存储到内存中,未查询和引用其他表数据提供快速访问。每一个表实际上和一个磁盘文件关联,文件是frm。支持的数据类型有限制(不支持TEXT和BLOB类型)
(1)支持的锁粒度为表级锁。所以在访问量比较大时,表级锁会成为MEMORY存储引擎的瓶颈。
(2)由于数据是存放在内存中,一旦服务器出现故障,数据都会丢失
(3)MEMORY存储引擎支持HASH和BTREE索引。
MySQL事务
什么是事务?
事务是一组操作,这些操作要么全部成功,要么全部失败,可以通过使用事务来确保数据库的完整性和一致性。
事务隔离级别是指在多个并发事务同时访问数据库时,每个事务所能读取和修改的数据范围。MySQL中提供了四个事务隔离级别:读未提交、读已提交、可重复读和串行化。
事务需要隔离级别是因为当多个并发事务同时访问数据库时,可能会出现以下问题:
- 脏读:一个事务读取到另一个事务未提交的数据,未提交意味着这些数据可能会回滚,也就是可能最终不会存到数据库中,也就是不存在的数据。读到了并一定最终存在的数据,这就是脏读。
- 不可重复读:一个事务多次读取同一数据,但每次读取的结果不同
- 幻读:幻读是针对数据插入(INSERT)操作来说的。假设事务A对某些行的内容作了更改,但是还未提交,此时事务B插入了与事务A更改前的记录相同的记录行,并且在事务A提交之前先提交了,而这时,在事务A中查询,会发现好像刚刚的更改对于某些数据未起作用,但其实是事务B刚插入进来的,让用户感觉很魔幻,感觉出现了幻觉,这就叫幻读【一个事务多次读取同一数据,但每次读取的结果行数不同】。
通过设置适当的事务隔离级别,可以避免以上问题的发生,确保数据的正确性和一致性。
注意:
可重复读指的是在一个事务内,最开始读到的数据和事务结束前的任意时刻读到的同一批数据都是一致的。通常针对数据更新(UPDATE)操作。
事务隔离级别
SQL 标准定义了四种隔离级别,MySQL 全都支持。这四种隔离级别分别是:
- 读未提交(READ UNCOMMITTED)
- 读提交 (READ COMMITTED)
- 可重复读 (REPEATABLE READ)
- 串行化 (SERIALIZABLE)
从上往下,隔离强度逐渐增强,性能逐渐变差。采用哪种隔离级别要根据系统需求权衡决定,其中,可重复读是 MySQL 的默认级别。
事务特性
事务具有原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)四个特性,简称 ACID,缺一不可。今天要说的就是隔离性。
MySQL锁级别分类
MySQL中的锁级别可以分为两种:共享锁(Shared Lock)和排他锁(Exclusive Lock)。
- 共享锁(Shared Lock)
共享锁也称为读锁,它可以让多个事务同时对同一数据进行读取,但是不允许进行写入操作。共享锁之间不会相互阻塞,因此多个事务可以同时持有同一个共享锁。
在MySQL中,可以使用SELECT ... LOCK IN SHARE MODE语句获取共享锁。
- 排他锁(Exclusive Lock)
排他锁也称为写锁,它可以让一个事务对数据进行写入操作,同时阻塞其他事务对该数据的读取和写入操作。排他锁之间会相互阻塞,因此只有一个事务可以持有排他锁。
在MySQL中,可以使用SELECT ... FOR UPDATE或UPDATE等语句获取排他锁。
除了以上两种锁级别之外,MySQL还支持表锁和行锁。表锁是对整张表进行加锁,可以保证整张表的一致性,但是会对性能产生较大的影响。行锁是对表中的行进行加锁,可以提高并发性,但是会增加锁的粒度,可能会导致死锁等问题的发生。因此,在使用锁机制时,需要根据具体情况选择适当的锁级别。
MySQL锁级别
MySQL中的锁级别可以分为四种,从低到高分别是:
- 读未提交(Read Uncommitted)
在该级别下,事务可以读取到其他事务未提交的修改,称之为脏读(Dirty Read)。该级别的隔离性最低,容易出现并发问题,不建议使用。
- 读已提交(Read Committed)
在该级别下,事务只能读取到其他事务已经提交的修改。该级别可以避免脏读问题,但是由于其他事务可能在同一时间内提交修改,因此可能会出现不可重复读(Non-Repeatable Read)的问题。
- 可重复读(Repeatable Read)
在该级别下,事务能够多次读取同一数据,保证读取结果的一致性。该级别可以避免不可重复读问题,但是由于其他事务可能在同一时间内提交新的修改,因此可能会出现幻读(Phantom Read)的问题。
- 序列化(Serializable)
在该级别下,事务串行执行,保证最高的隔离性和一致性,但是会对并发性能产生较大的影响。
除了以上四种锁级别之外,MySQL还支持表锁和行锁。表锁是对整张表进行加锁,可以保证整张表的一致性,但是会对性能产生较大的影响。行锁是对表中的行进行加锁,可以提高并发性,但是会增加锁的粒度,可能会导致死锁等问题的发生。因此,在使用锁机制时,需要根据具体情况选择适当的锁级别。
MySQL锁级别与事务隔离级别的区别
MySQL中的锁级别和事务隔离级别是两个不同的概念,虽然它们都与并发控制相关,但是它们的作用和实现方式不同。
锁级别是指在并发访问数据库时,控制对数据的读写访问的粒度,以避免不同事务之间的冲突。MySQL支持多种锁级别,从低到高分别是读未提交、读已提交、可重复读和串行化。
事务隔离级别则是指在多个事务并发执行时,保证每个事务之间相互隔离,避免因并发操作导致的数据不一致问题。MySQL支持四种隔离级别,从低到高分别是读未提交、读已提交、可重复读和串行化。
锁级别和事务隔离级别之间的关系是:隔离级别决定了一个事务能够读取到哪些数据,而锁级别则决定了一个事务能够对哪些数据进行读写访问。也就是说,隔离级别决定了数据的可见性,而锁级别决定了数据的可修改性。
在实际应用中,需要根据具体情况选择适当的锁级别和隔离级别。一般来说,隔离级别越高,数据的一致性和安全性就越高,但是并发性能也会相应降低;而锁级别越高,数据的一致性和安全性也会提高,但是会对并发性能产生较大的影响。
问题及描述
问题一:
两个程序同时读取mysql5.7表中某一行记录,一条做编辑操作,一条做修改操作,mysql5.7是否默认自带有加锁机制?如果有,那默认的锁机制是什么?
MySQL 5.7 默认使用行级锁机制,即在对行数据进行修改、删除等操作时,只会锁定该行数据,而不是整张表,因此可以支持更高的并发性和可扩展性。
在上述情况下,当两个程序同时读取 MySQL 5.7 表中某一行记录并进行编辑和修改操作时,MySQL 5.7 会自动加锁,保证并发操作的正确性和一致性。具体来说,MySQL 5.7 会根据事务的隔离级别和操作类型,自动加上相应的锁,以保证数据的一致性和完整性。
在默认情况下,MySQL 5.7 采用的是可重复读(REPEATABLE READ)隔离级别,即在事务开始时,会将当前的数据快照存储在事务中,事务中的所有操作都是基于这个快照进行的,所以可以避免脏读、不可重复读和幻读等问题。对于修改操作,MySQL 5.7 会自动加上排他锁(X锁),防止其他事务修改该行数据,对于编辑操作,MySQL 5.7 会自动加上共享锁(S锁),防止其他事务同时进行编辑操作。当事务提交或回滚后,MySQL 5.7 会自动释放相应的锁,以保证数据的一致性和完整性。
问题二:
当两个程序同时读取Mysql5.7表中某一行记录并进行编辑和修改操作,这个编辑和修改不是同一个操作么?
对于MySQL 5.7中的行级锁机制来说,编辑和修改操作不是同一个操作。具体来说,编辑操作和修改操作都会对该行数据进行操作,但是它们的操作类型不同,因此 MySQL 5.7 会根据操作类型自动加上相应的锁。
编辑操作一般是指对该行数据进行读取,但不会对数据进行修改,因此 MySQL 5.7 会自动加上共享锁(S锁),以防止其他事务修改该行数据。而修改操作则是指对该行数据进行更新、删除等操作,因此 MySQL 5.7 会自动加上排他锁(X锁),以防止其他事务同时进行修改操作。因此,在两个程序同时读取 MySQL 5.7 表中某一行记录并进行编辑和修改操作时,它们的操作类型不同,MySQL 5.7 会自动加上相应的锁,以保证数据的一致性和完整性。
问题三:
MySQL存储引擎不支持事务,或使用非安全事务时,那么相应表是否支持锁机制?MySQL锁机制是建立在什么基础上?
如果MySQL存储引擎不支持事务,或使用非安全事务时,相应表仍然支持锁机制。MySQL锁机制是建立在数据库管理系统(DBMS)的基础上,主要用于控制并发访问的数据一致性和完整性。MySQL锁机制包括两种类型的锁:共享锁和排他锁。共享锁允许多个事务同时访问同一数据,但只能读取,不能修改。排他锁则只允许一个事务访问数据,并且可以读取和修改。锁机制可以保证事务在读取和修改数据时不会发生冲突,并且可以保证数据的一致性和完整性。
问题四:
MySQL的9种存储引擎都支持共享锁或排他锁么?这两种锁在什么级别会生效?
不是所有的MySQL存储引擎都支持共享锁或排他锁,不同的存储引擎在锁机制方面的支持程度是不同的。例如,InnoDB存储引擎支持共享锁和排他锁,而MyISAM存储引擎只支持表级锁,不支持行级锁。
共享锁和排他锁在不同的级别会生效。在InnoDB存储引擎中,共享锁和排他锁可以在行级别生效,也可以在表级别生效。在行级别时,共享锁和排他锁分别用于控制并发读和并发写,即多个事务可以同时读取同一行数据,但只能有一个事务修改该行数据。在表级别时,共享锁和排他锁用于控制整个表的读写操作,即多个事务可以同时读取同一表的数据,但只能有一个事务修改该表的数据。在MyISAM存储引擎中,锁机制只能在表级别生效,因此只能使用表级共享锁和表级排他锁。
问题五:
MySQL共享锁、排他锁、表级锁、行级锁的区别?
MySQL共享锁和排他锁不必须同时联合在一起使用,它们是两种不同的锁机制,可以单独使用或组合使用。
在MySQL中,共享锁和排他锁是用于控制并发访问的数据一致性和完整性的锁机制。共享锁用于多个事务同时读取同一数据,但不能修改;排他锁则只允许一个事务访问数据,并且可以读取和修改。共享锁和排他锁可以分别应用于不同的场景,也可以组合使用。例如,在读取数据时可以使用共享锁,而在修改数据时需要使用排他锁。
需要注意的是,共享锁和排他锁会对数据库的性能产生一定的影响,因此在使用时需要根据具体的业务需求进行权衡和选择,避免过度使用锁机制导致性能下降。
MySQL的共享锁、排他锁、表级锁和行级锁是用于控制并发访问的数据一致性和完整性的锁机制,它们之间的区别如下:
- 共享锁和排他锁:共享锁允许多个事务同时读取同一数据,但不能修改。排他锁则只允许一个事务访问数据,并且可以读取和修改。
- 表级锁和行级锁:表级锁锁定整个表,可以控制整个表的读写操作。行级锁锁定表中的一行或多行,可以控制并发读和并发写操作。
- 共享锁和排他锁的区别在于,共享锁可以被多个事务同时持有,但是排他锁只能被一个事务持有。如果一个事务持有了排他锁,则其他事务不能同时持有共享锁或排他锁。
- 表级锁和行级锁的区别在于,表级锁锁定整个表,可以控制整个表的读写操作,但是会对并发性产生较大的影响。行级锁只锁定表中的一行或多行,可以提高并发性,但是会增加锁的粒度和锁的开销。
总之,不同的锁适用于不同的场景,需要根据具体的需求选择合适的锁机制。
问题六:
MySQL事务已定义隔离级别后,还需要针对表中数据实行加锁机制么
MySQL中的事务隔离级别是通过锁机制来实现的,因此在定义了隔离级别之后,MySQL会自动对数据进行加锁。
在MySQL中,事务隔离级别越高,加锁的程度就越高,因此会对性能产生一定的影响。如果应用程序的并发性不是很高,可以选择较低的隔离级别,减少加锁的程度,提高性能。但是,如果应用程序需要保证数据的完整性和一致性,就必须选择较高的隔离级别,并且需要对表中的数据进行加锁。
在MySQL中,可以通过使用SELECT ... FOR UPDATE语句对数据进行加锁,也可以使用INSERT ... ON DUPLICATE KEY UPDATE、UPDATE和DELETE等语句对数据进行加锁。需要注意的是,在使用加锁机制时,应该尽量减少锁的范围,以避免对性能的影响。
问题七:
MySQL不对针对表或表中数据,默认存在加锁机制么,什么还需要使用select或insert进行加锁?
MySQL中默认情况下,在进行读写操作时,会对表或表中数据进行加锁,以确保事务的隔离性和一致性。但是,MySQL的默认锁机制并不是非常严格,如果应用程序需要更高的隔离级别或更严格的锁机制,就需要使用SELECT或INSERT等语句进行加锁。
在MySQL中,可以通过使用SELECT ... FOR UPDATE语句对数据进行加锁,以确保在事务提交之前,其他事务无法修改该数据。例如:
BEGIN;
SELECT * FROM table WHERE id = 1 FOR UPDATE;
-- 对数据进行操作
COMMIT;
在以上代码中,SELECT语句使用了FOR UPDATE子句,表示对查询结果进行加锁,其他事务无法修改该数据,直到当前事务提交或回滚。
类似地,INSERT ... ON DUPLICATE KEY UPDATE、UPDATE和DELETE等语句也可以使用加锁机制,以确保在事务提交之前,其他事务无法修改相应的数据。
需要注意的是,在使用加锁机制时,应该尽量减少锁的范围,以避免对性能的影响。同时,也要避免死锁等问题的发生。