文章目录
- 一、什么是事务(Transaction)
- 二、事务管理ACID的原则
- 1.原子性(Atomicity)
- 2.一致性(Consistency)
- 3.持久性(Durability)
- 4.隔离性(Isolation)
- 1)隔离(并发执行下)导致的问题
- 2)隔离级别
- 3)隔离级别的实现(InnoDB)
- · 锁机制
- · MVCC机制
- 三、事务的代码实现
- 1. TIPS
- 2. 步骤
本系列根据B站教学视频进行的知识点整理总结。
一、什么是事务(Transaction)
事务是访问数据库的一个操作序列,数据库应用系统通过事务集来完成对数据库的存取。事务的正确执行使得数据库从一种状态转换为另一种状态。在关系数据库中,一个事务可以是一条SQL语句,一组SQL语句或整个程序。事务需满足ACID原则才是一个正确的事务。
二、事务管理ACID的原则
1.原子性(Atomicity)
“要么都成功,要么都失败”
举例:
1.SQL执行:A给B转账,A当前余额1000元,B当前余额200元,A向B转账200元。
2. SQL执行:B收到A转账的钱,此时A余额为800元,B余额400元。
事务就是需要将1/2两条SQL语句放在同一个批次去执行,两条语句要不都执行成功,要不都执行失败。否则,若只执行第一条语句,未执行语句2则会出现:A对B进行转账,A的余额变成800,但B未接收到A的转账,B的余额还是200,则出错。
2.一致性(Consistency)
“某一事务操作前后的数据保持一致”
举例:
操作前:A + B = 1200
操作后:A + B = 1200
3.持久性(Durability)
“事务没有提交,恢复到原状;事务提交了,持久化到数据库”
举例:
操作前:A=1000 B=200
操作:A向B转账200元,B收到A转账的钱。
事务若没提交,服务器宕机或者断电,数据库重启后:A=1000 B=200
事务若已提交,服务器宕机或者断电,数据库重启后:A=800 B=400
4.隔离性(Isolation)
“事务之间相互独立,中间状态不可见”
举例:
操作1:A:1000 B:200 (A转账给B 200)
操作2:C:300 (C转账给B 100)
1)隔离(并发执行下)导致的问题
1> 脏读:一个事务读取了另一个事务未提交的数据
举例:
事务1:
提交前:A:1000 B:200 A转账给B 200
提交后:A:800 B:400
事务2:
提交前:C:300 B:200 C转账给B 100 (读取了事务1提交前B的数据)
提交后:C:200 B:300
2> 不可重复读:在一个事务内读取表中某一行数据,多次读取的结果不同。
第一次读取B:A:1000 B:200
第二次读取B:A:1000 B:500(其他事务又改变了B的值)
3> 虚读(幻读):一个事务内读取了另一个事务插入的数据,导致读取前后不一致。(第一次读C不存在,第二次读C就存在了)
读取前:A:1000 B:200
读取后:A:1000 B:200 C:300 (C为另一个事务插入的数据)
2)隔离级别
为解决脏读、不可重复读、幻读指定的标准。
1> read-uncommitted 已读未提交:最低级别,能够读取到没有被提交的数据,只能保证持久性。
2> read-committed 已读已提交: 语句级别的,可解决脏读。
3> repeatable-read 可重复读:事务级别。可解决脏读、不可重复读。
4> serializable 串行化:最高级别,事务与事务完全串行化执行,毫无并发可言,性能极低。可解决脏读、不可重复读、幻读。
3)隔离级别的实现(InnoDB)
(后续继续学习后补充代码实现)
· 锁机制
当一个事务执行的时候,阻止其他事务对数据进行操作。各个隔离级别主要体现在读取数据时加锁的时机和释放时机。
1> read-uncommitted 已读未提交:事务读取的时候,不加锁。
2> read-committed 已读已提交: 事务读取的时候加行级共享锁(读到加锁),一旦读完,立即释放锁(并不是事务的结束)。
3> repeatable-read 可重复读:事务读取的时候加行级共享锁,直到事务结束锁才释放。
4> serializable 串行化:事务读取的时候加表级共享锁,直到事务结束锁才释放。
· MVCC机制
生成一个数据快照,并用这个快照来提供一定级别的一致性的读取,也成为了多版本数据控制。
1>实际是 CAS版本控制 和 读写分离 的思想。
2>主要用于 read-committed 已读已提交 和 repeatable-read 可重复读。
三、事务的代码实现
1. TIPS
1)mysql默认开启事务自动提交
SET autocommit = 0 /*关闭自动提交*/
SET autocommit = 1 /*开启自动提交*/
2)可在一个事务操作过程中设置保存点
SAVEPOINT 保存点名 /*设置一个保存点*/
ROLLBACK TO 保存点名 /*回滚到该保存点*/
RELEASE SAVEPOINT 保存点名 /*删除一个保存点*/
2. 步骤
-- 1.关闭自动提交,手动处理事务
SET autocommit = 0
-- 2.事务开启
START TRANSACTION
-- 3.对数据进行操作
INSERT
UPDATE
...
-- 4.操作成功后,提交操作后的数据结果
COMMIT
-- 或者操作失败后,回滚至原来的样子
ROLLBACK
-- 5.事务结束,开启事务自动提交
SET autocommit = 1
例:账户A 给账户B 转账
-- 1. 创建一个数据库
CREATE DATABASE bank CHARACTER SET utf8 COLLATE utf8_general_ci
-- 2. 对该数据库操作
USE bank
-- 3. 创建一个表
CREATE TABLE `account`(
`id` INT(3) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(30) NOT NULL,
`money` DECIMAL(9,2) NOT NULL,
PRIMARY KEY (`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
-- 4. 添加数据
INSERT INTO `account`(`name`,`money`)
VALUES('A',1000),('B',2000)
-- 5.实现一个转账事务
SET autocommit = 0
START TRANSACTION
UPDATE `account` SET money = money - 500 WHERE `name` = 'A' -- A=500
UPDATE `account` SET money = money + 500 WHERE `name` = 'B' -- B=2500
ROLLBACK -- A=1000 B=2000
COMMIT -- A=500 B=2500
SET autocommit = 1