什么是事务
事务是一组数据库操作序列,是一个不可分割的单位。这些操作要么全做,要么不做。
事务的ACID特性
原子性(Atomicity)
事务必须作为一个完整的、不可分割的单位被执行。事务中所做的这些操作,要么全做,要么不做。
一致性(Consistency)
事务操作前后数据库应该由一个一致的状态转变为另一个一致的状态。一致状态的含义是数据库中的数据数据应满足完整性约束。
隔离性(Isolation)
多个事务并发执行时,一个事务的执行不能影响其他事务的执行。
持久性(Durability)
已被提交的事务对数据库的修改会被永久保存在数据库中。
事务并发存在的问题
为了更好地描述问题,我们创建一张MySQL数据库表。
CREATE TABLE `accounts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(64) NOT NULL,
`balance` int(11) NOT NULL DEFAULT 0,
PRIMARY KEY(`id`),
UNIQUE KEY(`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
复制代码
INSERT INTO accounts(`name`, `balance`) VALUES('John', 100);
复制代码
脏读(Dirty Read)
脏读也叫未提交读,指的是事务A读取到了事务B未提交的修改。
- 事务B: begin;
- 事务B: update accounts set balance = balance - 20 where name = 'John';
- 事务A: begin;
- 事务A: select balance from accounts where name = 'John';
- 事务B: rollback;
由于事务B进行了回滚,账户里还是有100元,而事务A却读到账户里的金额为80元。
不可重复读(Unrepeatable Read)
- 事务A: begin;
- 事务A: select balance from accounts where name = 'John'; 得到100
- 事务B: begin;
- 事务B: update accounts set balance = balance - 20;
- 事务B: commit; balance变为80
- 事务A: select balance from accounts where name = 'John'; 得到80
事务A两次读取同一数据得到的金额一次为100元一次为80元,这就叫不可重复读。
幻读(Phantom Read)
幻读指的是在一次事务中执行相同的查询,得到结果的条数发生了变化。
- 事务A: begin;
- 事务A: select * from accounts; 得到1条记录
- 事务B: begin;
- 事务B: insert into accounts(`name`, `balance`) values('Mike', 90);
- 事务B: commit;
- 事务A: select * from accounts; 得到2条记录
事务A两次执行查询账户操作,一次得到1条记录另一次得到2条记录,这就叫幻读。
MySQL事务隔离级别
MySQL有4种事务隔离级别,默认的是可重复读。但我们也可以自行设置MySQL的事务隔离级别。
读未提交(Read Uncommitted)
设置MySQL事务隔离级别为读未提交。
set session transaction isolation level read uncommitted;
复制代码
可以发现会出现脏读的问题。
读已提交(Read Committed)
set session transaction isolation level read committed;
复制代码
可以发现解决了脏读的问题但是会出现不可重复读的问题。
可重复读(Repeatable Read)
set session transaction isolation level repeatable read;
复制代码
可以发现解决了不可重复读的问题.
注意:可重复读的隔离级别不能解决幻读的问题。
可串行化(Serializable)
所有事务将会串行执行。