1. 什么是事务?为什么需要事务?
在关系数据库中,一个事务可以是一条SQL语句,一组SQL语句或整个程序。这个就是事务。
为什么需要事务呢?因为我们在在做某件事情的时候,往往会有一系列的操作,我们希望事情的圆满完成,在完成过程中所遵循的规则就是事务的特征。
2. 事务的特征
事务的特征简称ACID。即为原子性,一致性,隔离性和持久性。
- 原子性
在做某件事情的时候,我们希望所做的操作,要么全部成功,要么全部失败。这个操作过程不可分割,叫做事务的原子性。 - 一致性
在做某件事情的过程中,从开始到结束,总在我们的预期范围内,不会出现中间状态,在操作的前后都符合我们的业务规则。例如转账中,A账户想B账户转账100元,两账户的总金额是恒定的。 - 隔离性
隔离性是讲多个事务之间,当一个事务对数据进行操作的时候,其他事务不能同时对这个数据进行操作,并发的事务之间不会相互干扰。 - 持久性
持久性就是数据的持久化,一旦操作就会产生结果是永久性的。即使出现错误也不会产生影响。
3. 手动提交事务
MySQL是自动提交事务。
也可以修改成手动提交事务,但是一般情况下无需修改。
开始 begin;或者 start transaction; 开始事务
执行业务
commit; 提交 或者 rollback; 回滚
4. 事务的隔离级别
事务的隔离级别有读未提交,读已提交,可重复读,串行化四种。
- 串行(serializable):事务和事务之间具有隔离性,事务之间的完全隔离,也就是一个事务操作完成才会释放锁,之后才会交给其他事务来操作。完全的隔离就是串行化。串行化的时候操作数据会添加共享锁,并发的时候会产生锁竞争和超时。
- 可重复度RR (Repetable Read)
MySQL的默认事务隔离级别。当数据在写操作的时候,其他的时候可以重复读取,并在数据写操作过程中不会发生变化。避免了脏读和不可重复度的情况。
到底RR级别有没有解决幻读的情况,可以这么说,解决了一部分的幻读情况。MySQL查询数据的时候存在当前读和快照读两种方式。当前读的情况仍然会产生幻读。快照读先执行其他事务插入的操作,再执行查询也是可以查询到当前数据的。
幻读的情况参考文章 [https://www.jianshu.com/p/4c02a3a2e9d2](https://www.jianshu.com/p/4c02a3a2e9d2)
个人又验证了一番,此处更改,可以参考博主文章 MySQL幻读以及当前读引起的问题验证 - 读已提交 RC (Read Commited)
Oracle 默认的隔离级别。就是可以读取到其他事务提交的数据,允许快照读中幻读的情况发生。 - 读未提交 RU (Read UnCommited)
生产过程中不建议使用,因为会读取到其他事务未提交的事务数据。
产生的现象叫做脏读。
5. 脏读,幻读,不可重复读
脏读,不可重复读和幻读是事务在查询数据时,有其他事务同时对数据进行操作所查询到的异常情况。
- 脏读
读取了其他事务未提交的数据。 - 不可重复读
读取时过程中出现了数据修改。常见于update操作。 - 幻读
在读取的时候出现了其他事务新插入的数据。常见于 insert操作。
6. 测试总结
测试示例:
- 表结构:
- 表数据
- 验证事务的隔离性
-- 事务1
begin;
update user set name = "lisi" where id = 2;
-- 事务2
begin;
select * from user where id = 2;
事务2 结果仍然是事务1更改之前的结果:
6.2 验证事务手动提交
继续6.1 的测试
-- 事务1 提交事务
commit;
-- 事务2 查询
commit;
select * from user where id = 2;
事务2查询结果:
当然即使是事务2先查询,后commit 结果 name 的值仍然是 ‘zhangsan’,因为查询的时候拿到的是之前的数据。
脏读,不可重复读和幻读的情况可以通过修改事务的隔离级别来验证。此处就不一一验证了。修改隔离级别SQL 语句:
SET session TRANSACTION ISOLATION LEVEL 隔离级别;
其中的隔离级别可以是 Read uncommitted,Read committed,Repeatable,Serializable 。