关于MySQL中事务的先容
事务的四大隔离级别及其所办理的读现象如下:
在DBMS中,事务保证了一个操纵序列可以全部都实行或者全部都不实行(原子性),从一个状态变化为另一个状态(一致性)。由于事务满意持久性,所以一旦事务被提交之后,数据就能够被持久化下来,又由于事务是满意隔离性的,所以,当多个事务同时处置惩罚同一个数据的时间,多个事务直接是互不影响的,所以,在多个事务并发操纵的过程中,如果控制不好隔离级别,就有可能产生脏读、不可重复读、丢失修改、或者幻读等读现象。
在数据库事务的ACID四个属性中,隔离性是一个最常放松的一个。可以在数据库操纵中利用数据库的锁机制或者多版本并发控制机制来获取更高的隔离级别。但是,随着数据库隔离级别的进步,数据的并发能力也会有所降落。所以,如何在并发性和隔离性之间做一个和很好的衡量就成了一个至关紧张的题目。
ANSI/ISO SQL定义的标准隔离级别有四种,从高到底依次为:可序列化(Serializable)、可重复读(Repeatable reads)、提交读(Read committed)、未提交读(Read uncommitted)。
下面将依次先容这四种事务隔离级别的概念、用法以及办理了哪些题目(读现象)
事务的隔离级别定义了一个事务对其他事务的可见性,MySQL支持四种隔离级别,从低到高分别为:
- 读未提交(Read Uncommitted)
定义:这是最低的隔离级别,在这个级别下,一个事务可以读取到其他事务尚未提交的数据。
办理的题目:无。
存在的题目:脏读(Dirty Read)、不可重复读(Non-Repeatable Read)、幻读(Phantom Read)。
实现原理:锁机制:几乎不使用任何锁,事务可以读取其他事务尚未提交的数据。
- -- transaction a
- start transaction;
- update accounts set balance = balance - 100 where user_id = 1;
-
- -- transaction b
- start transaction;
- select balance from accounts where user_id = 1; -- 可能读取到未提交的数据
- commit;
-
- -- transaction a
- rollback;
复制代码
- 读已提交(Read Committed)
定义:在这个隔离级别下,一个事务只能读取到其他事务已经提交的数据。
办理的题目:办理了脏读题目,进步了数据一致性。
存在的题目:不可重复读、幻读。
实现原理--锁机制:事务在读取数据时会使用共享锁(S锁),但在事务提交后会开释这些锁。因此,事务只能读取到其他事务已经提交的数据。
- -- transaction a
- start transaction;
- update accounts set balance = balance - 100 where user_id = 1;
- commit;
-
- -- transaction b
- start transaction;
- select balance from accounts where user_id = 1; -- 读取到事务a提交后的数据
- commit;
复制代码
- 可重复读(Repeatable Read)
定义:这是MySQL的默认隔离级别。在这个级别下,一个事务在整个实行期间看到的数据是一致的,即多次读取同一数据的结果雷同,即使其他事务在这期间对数据举行了修改并提交。
办理的题目:办理了脏读和不可重复读题目,进步了数据一致性。
存在的题目:幻读。
实现原理--锁机制:事务在读取数据时会使用多版本并发控制(MVCC),确保事务在这个行期间看到的数据是一致的。MySQL使用快照读(Snapshot Read)来实现这一点。
- -- transaction a
- start transaction;
- select balance from accounts where user_id = 1; -- 第一次读取
- update accounts set balance = balance - 100 where user_id = 1;
- commit;
-
- -- transaction b
- start transaction;
- select balance from accounts where user_id = 1; -- 读取到事务a开始前的数据
- commit;
复制代码
- 序列化(Serializable)
定义:这是最高的隔离级别,通过强制事务串行实行来避免并发题目。在这个级别下,事务完全按照序次实行,不会出现并发操纵。
办理的题目:办理了全部读现象题目,包括脏读、不可重复读和幻读。
存在的题目:性能较低,由于事务需要排队实行,可能会导致系统吞吐量降落。
实现原理--锁机制:事务通过强制事务串行实行来避免并发题目。MySQL使用表级锁或行级锁来实现这一点,确保事务完全按照序次实行。
- -- transaction a
- start transaction;
- select * from accounts where user_id = 1 for update; -- 获取排他锁
- update accounts set balance = balance - 100 where user_id = 1;
- commit;
-
- -- transaction b
- start transaction;
- select * from accounts where user_id = 1 for share; -- 需要等待事务a释放排他锁
- commit;
复制代码
读现象表明:
- 脏读(Dirty Read):一个事务读取了另一个事务未提交的数据
- 不可重复度(Non-Repeatable Read:一个事务在两次查询之间,另一个事务对数据举行了修改并提交,导致同一个事务在不同时间读取统一数据得到了不同的结果。
- 幻读:(Phantom Read):一个事务在两次查询之间,另一个事务插入了新的数据行,导致第一个事务在第二次查询时看到了之前不存在的数据行。
数据库中的共享锁与排他锁
在数据库中,锁机制是确保数据一致性和并发控制的紧张手段。共享锁(Shared Lock,简称S锁)和排他锁(Exclusive Lock,简称X锁)是最基本的两种锁类型。下面详细先容这两种锁的特性、用途以及它们之间的关系。
共享锁(Shared Lock,S锁)
定义:共享锁也称为读锁,允很多个事务同时读取同一数据项,但不允许任何事务修改该数据项。
特性:
- 共享性:多个事务可以同时持有同一数据项的共享锁。
- 互斥性:如果一个事务持有一个数据项的共享锁,其他事务不能对该数据项加排他锁。
用途:
- 读操纵:主要用于读取数据,确保读取过程中数据不会被其他事务修改。
示例:
- -- 事务A
- START TRANSACTION;
- SELECT * FROM accounts WHERE user_id = 1 FOR SHARE; -- 获取共享锁
- COMMIT;
-
- -- 事务B
- START TRANSACTION;
- SELECT * FROM accounts WHERE user_id = 1 FOR SHARE; -- 可以获取共享锁
- COMMIT;
复制代码 排他锁(Exclusive Lock,X锁)
定义:排他锁也称为写锁,允许一个事务独占性地访问某一数据项,禁止其他事务读取或修改该数据项。
特性:
- 独占性:在同一时间,只有一个事务可以持有某一数据项的排他锁。
- 互斥性:如果一个事务持有一个数据项的排他锁,其他事务不能对该数据项加任何类型的锁(包括共享锁和排他锁)。
用途:
- 写操纵:主要用于修改数据,确保修改过程中数据不会被其他事务读取或修改。
示例:
- -- 事务A
- START TRANSACTION;
- SELECT * FROM accounts WHERE user_id = 1 FOR UPDATE; -- 获取排他锁
- UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
- COMMIT;
-
- -- 事务B
- START TRANSACTION;
- SELECT * FROM accounts WHERE user_id = 1 FOR SHARE; -- 需要等待事务A释放排他锁
- COMMIT;
复制代码 共享锁与排他锁的关系
- 兼容性:
- 共享锁与共享锁:兼容,多个事务可以同时持有同一数据项的共享锁。
- 共享锁与排他锁:不兼容,如果一个事务持有一个数据项的共享锁,其他事务不能对该数据项加排他锁。
- 排他锁与排他锁:不兼容,如果一个事务持有一个数据项的排他锁,其他事务不能对该数据项加任何类型的锁。
- 锁转换:
- 共享锁转排他锁:通常不允许直接将共享锁转换为排他锁,需要先开释共享锁,再加排他锁。
- 排他锁转共享锁:可以直接将排他锁降级为共享锁,但通常不需要这样做,由于排他锁已经确保了独占性。
MySQL 的行级锁与表级锁
在 MySQL 中,锁机制是保证并发控制和数据一致性的关键。根据锁的作用范围不同,主要分为行级锁和表级锁。
表级锁
- 定义:表级锁是 MySQL 中最基本的锁计谋,也是最粗粒度的锁。当一个事务对某个表举行操纵时,会锁定整个表,其他事务不能对该表举行任何修改操纵。
- 长处:
- 缺点:
- 适用场景:
- 适用于读多写少的场景,或者对数据一致性要求不高的场景。
- 示例:
- MyISAM 存储引擎使用表级锁。
- InnoDB 存储引擎在某些情况下也会使用表级锁,例如在实行 LOCK TABLES 语句时。
- -- MyISAM 存储引擎
- CREATE TABLE myisam_table (
- id INT PRIMARY KEY,
- name VARCHAR(50)
- ) ENGINE=MyISAM;
-
- -- 插入数据
- INSERT INTO myisam_table (id, name) VALUES (1, 'Alice'), (2, 'Bob');
-
- -- 事务1
- START TRANSACTION;
- UPDATE myisam_table SET name = 'Charlie' WHERE id = 1;
-
- -- 事务2
- START TRANSACTION;
- UPDATE myisam_table SET name = 'David' WHERE id = 2; -- 会被阻塞,直到事务1提交或回滚
复制代码
行级锁
- 定义:行级锁是 MySQL 中最细粒度的锁,只锁定需要操纵的行。行级锁可以最大限度地支持并发操纵,但实现复杂,开销较大。
- 长处:
- 锁粒度小,能够支持高并发。
- 减少了锁冲突的概率,进步了系统的并发性能。
- 缺点:
- 适用场景:
- 适用于写多读少的场景,或者对数据一致性要求较高的场景。
- 示例:
- InnoDB 存储引擎默认使用行级锁。
- 在 InnoDB 中,可以通过 SELECT ... FOR UPDATE 和 SELECT ... LOCK IN SHARE MODE 来显式地获取行级锁。
- -- InnoDB 存储引擎
- CREATE TABLE innodb_table (
- id INT PRIMARY KEY,
- name VARCHAR(50)
- ) ENGINE=InnoDB;
-
- -- 插入数据
- INSERT INTO innodb_table (id, name) VALUES (1, 'Alice'), (2, 'Bob');
-
- -- 事务1
- START TRANSACTION;
- SELECT * FROM innodb_table WHERE id = 1 FOR UPDATE;
-
- -- 事务2
- START TRANSACTION;
- SELECT * FROM innodb_table WHERE id = 2 FOR UPDATE; -- 不会被阻塞,因为锁定的是不同的行
复制代码
行级锁和表级锁对比
死锁及其办理方法
- 定义:死锁是指两个或多个事务在等待对方开释锁,从而导致全部事务都无法继续实行的情况。
- 检测:
- MySQL 会定期检测死锁,并选择一个事务举行回滚以排除死锁。
- 预防:
- 只管减少事务的持有锁时间。
- 按照固定的序次访问资源。
- 使用超时机制,避免长时间等待。
- 办理:
- 使用 SHOW ENGINE INNODB STATUS 检察当前的死锁信息。
- 分析日志,找出死锁的原因并优化事务逻辑。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |