事务是一组操作的集合,他是不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功要么同时失败。
默认mysql的事务是自动提交的,也就是说,当执行一条DML语句,mysql会立即隐式的提交事务。
事务的四大特性
- 原子性:事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
- 一致性:事务完成时,必须所有数据都保持一致状态。
- 隔离性:数据库提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
- 持久性:事务一旦提交或回滚,它对数据库中的数据的改变是永久的。
事务操作
- 查看/设置事务提交方式
SELECT @@autocommit;
SET @@autocommit = 0;
- 开启事务
START TRANSACTION 或 BEGIN;
- 提交事务
COMMIT;
- 回滚事务
ROLLBACK;
事务演示
#开启事务
START TRANSACTION;
SELECT * FROM userinfo;
#进行转账操作
UPDATE userinfo SET money = money - 1000 WHERE name = '狸花';
UPDATE userinfo SET money = money + 1000 WHERE name = '吾心悦';
#提交事务
COMMIT;
SELECT * FROM userinfo;
并发事务问题
问题 | 描述 |
脏读 | 一个事务读到另外一个事务还没提交的数据 |
不可重复读 | 一个事务先后读取同一条记录,但两次读取的数据不同 |
幻读 | 一个事务按照条件查询数据时,没有对应数据行,但是在插入数据时,又发现这一行数据已经存在。 |
事务隔离级别
隔离级别 | 脏读 | 不可重复读 | 幻读 |
Read uncommitted | ✓ | ✓ | ✓ |
Read committed | × | ✓ | ✓ |
Repeatable Read(默认) | × | × | ✓ |
Serializable | × | × | × |
查看事务隔离级别
SELECT @@TRANSACTION_ISOLATION;
设置事务隔离级别
SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED | READ COMMITTED |REPEATABLE READ |SERIALIZABLE]
查看事务隔离级别
设置事务隔离级别
Read uncommitted隔离级别下的脏读演示
用两个命令行模拟两个客户端进行演示
A端 设置隔离级别为Read uncommitted 开启事务 查询userinfo表数据
B端 开启事务 进行数据修改 未提交事务
A端 再次进行数据查询
B端开启事务执行更新后(未提交),A端查询 发现A端事务读取到B端事务未提交数据(脏读)
Read committed隔离级别下是否会出现脏读-演示
A端 设置事务隔离级别Read committed 开启事务 进行查询操作
B端 开启事务 进行数据修改 未提交事务
A端 查询表数据未发生变化
B端 事务进行提交
A端 再次查询表数据
B端事务进行提交后 A端才查询到表数据变化 该隔离级别下规避了脏读
Read committed隔离级别下不可重复读
借用上图在B端提交事务后A端事务中同样sql查询数据不一致(受其他事务影响),此问题称之为不可重复读
Repeatable Read隔离级别下解决不可重复读问题
A端 将隔离级别改为Repeatable Read 开启事务 进行表数据查询
B端 开启事务 进行表数据修改并提交
A端 再次查询
在一个事务中执行两次sql结果是一样(不受其他事务影响),为可重复读
A端 提交事务后再进行查询 数据发生变化
Repeatable Read隔离级别下幻读演示
A端 开启事务 查询userinfo表中id为4的数据
B端 开启事务 插入id为4的数据并提交
A端 插入id为4的数据 发现主键4重复了,再次查询id为4的数据还是没有,这种现象称之为幻读
Serializable隔离级别下解决幻读问题
A端 设置隔离级别为Serializable 查询表id为5的数据
B端 开启事务 插入id为5的数据 光标一直在闪发生阻塞(A端事务在操作要等其事务提交才能进行操作)
A端 插入id为5的数据并提交
B端 报错主键重复 规避了幻读问题
注意:事务隔离级别越高,数据越安全,但是性能越低。