事务是什么
事务是指,作为单个逻辑工作单元执行的一系列操作。
这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。
事务的4大特性
事务具有4个特性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)
原子性:事务作为一个整体执行,必须是原子工作单元,对数据进行修改时,要么全部执行,要么全部不执行。
一致性:在事务开始之前和完成之后,数据库确保是从一个一致性状态到另一个一致性,一致性状态的含义是数据库中的数据应满足完整性约束
隔离性:多个事务并发访问时,事务之间是隔离的,一个事务执行不影响其他事务执行
持久性:事务成功提交后,对数据的更改应该永久保存在数据库中,不会被回滚
事务的4种隔离级别
数据库事务的隔离级别有4个,由低到高依次为Read uncommitted、Read committed、Repeatable read、Serializable,这四个级别可以逐个解决脏读、不可重复读、幻读这几类问题。
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(Read Uncommitted) | yes | yes | yes |
读已提交(Read Committed) | no | yes | yes |
可重复读(Repeatable Read) | no | no | yes |
可串行化(Serializable) | no | no | no |
Read Uncommitted(读取未提交内容)
隔离级别中最低的一种,充许令外一个事务可以看到这个事务未提交的数据。如:事务A对数据做的修改,即使没有提交,对于事务B来说也是可见的。
在实际运用中会引起很多问题,因此一般不常用。这种隔离级别会产生脏读,不可重复读和幻像读。上述例子中就是脏读(Dirty Read)
,事务B读取到了事务A未提交的数据
Read Committed(读取提交内容)
此隔离级别下,保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。满足了隔离性的简单定义:一个事务只能看见已经提交事务所做的改变。
此时不会出现脏读的问题,事务A对数据做的修改,提交之后会对事务B可见。但会出现不可重复读(Nonrepeatable Read)
:在同一个事务中执行完全相同的select语句时可能看到不一样的结果。
简单来说就是事务A会多次读同一数据,如数据为1。在事务A执行第一次读数据后,事务B也访问数据1修改为了0并提交了事务,那么事务A执行第二次读数据时,读取到的就是0,两次读到的的数据就会不一样的。
不可重复读的重点是修改:
同样条件下,读取过的数据,再次读取发现结果不一致
Repeatable Read(可重读)
此隔离级别下,保证同一事务的多个实例在并发读取数据时,会看到同样的数据行。之前的例子中,事务B即便修改了同一数据1为0时,事务A多次读只会读取修改前的的数据1。
解决了不可重复读,但出现了幻读(Phantom Read)
:事务不是独立执行时发生的一种现象。多次读取一个范围内的记录发现结果不一致。
假设进行范围查询时,事务A第一次查询到10条记录为1的数据,事务A将所有为1的数据改为2,但还未提交时事务B插入了一条记录1的数据并提交了事务。那么事务A第二次读取时发现查询出11条,表中还存在没有修改的数据行,就好象发生了幻觉一样。
mysql中的Innodb 通过MVCC(多版本并发控制)来解决可重复读的情况下幻读的,但无法完全避免,还是需要配合锁机制来保证。
幻读的重点在于新增或者删除:
同样的条件,第 1 次和第 2 次读出来的记录数不一样
Serializable(可串行化)
这是最高最严格的隔离级别,它通过强制事务排序执行,使之不可能相互冲突,从而解决幻读问题。在这种隔离级别下,读取的每行数据都加锁,会导致大量的锁征用问题,大量的超时现象和锁竞争,性能最差。
什么情况适合使用事务
在进行多表或多sql组合操作时,为了保证结果达到一致性,需要用到事务。比如最典型的银行转账,需要确保一方金额的减少和一方金额的增加。
相关sql
查看隔离级别
-- 查看当前会话隔离级别
SELECT @@session.tx_isolation;
-- 查看系统当前隔离级别
SELECT @@tx_isolation;
设置隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL repeatable read;
-- SET SESSION TRANSACTION ISOLATION LEVEL 隔离级别(read uncommitted/read committed/repeatable read/serializable);
事务操作
-- 开始事务
START TRANSACTION;
-- 相关业务
SELECT * FROM xxx;
UPDATE xxx SET num =1 WHERE id = 1;
INSERT INTO xxx(id,num) VALUES(2,2);
-- 提交事务
COMMIT;
-- 或者回滚事务
-- ROLLBACK;
参考
https://www.cnblogs.com/phoebus0501/archive/2011/02/28/1966709.html
https://juejin.im/entry/5b835dfbf265da43531d0593
https://www.cnblogs.com/zhoujinyi/p/3437475.html
https://www.jianshu.com/p/ec52a27d3bf2
http://blog.sina.com.cn/s/blog_499740cb0100ugs7.html