数据库事务
什么是事务?
事务是一个不可分割的数据库操作序列,也是数据库并发的基本单位,其执行的结果是使数据库从一种状态变成另外一种一致性状态,是逻辑上的一组操作。要么全部执行,要么全部不执行
什么是数据库的四大特性ACID
- 原子性:事务执行的最小单位,不允许分割。事务的原子性确保动作要么全部完成、要么全部不起作用。例如转账,A转账B100块,A必须减少100,B增加100
- 一致性:执行事务前后,数据保持一致,多个事务对同一个数据的读取的结果是相同的
- 隔离性: 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间,数据库是独立的
- 持久性:一个事务被提交后,它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何的影响
SQL标准定义了四种隔离级别
什么是脏读?幻读?不可重复读?
脏读:某个事务已经更新了一份数据,另外一个事务在此时读取了同一份数据,由于某些原因,前一个事务RollBack操作,则后边一个事务所读取的数据就是不正确的。
不可重复读:在一个事务中,两次查询之中数据不一致,这可能是两次查询过程中插入了一个更新原有数据的事务。
幻读:在一个事务的两次查询中数据行数不一致。比如有一个事务查询了3行数据,而另外一个事务在此时新增了数据,先前事务在接下来的查询中,多了几行以前没有的数据。
- Read Uncommitted (读未提交),最低的隔离级别,顾名思义,允许读取未提交的数据变更。可能会导致脏读,幻读、或者不可重复读。
- Read Committed (读已提交),允许读取并发事务已经提交的事务,可以阻止脏读,但是幻读或不可重复读仍有可能发生
- Repeatable Read(可重复读),对同一字段的多次读取结果都是一致的,除非数据被本身事务锁修改,可以阻止脏读和不可重复读,但是幻读有可能发生
- Serializable(可串行化), 最高的事务隔离级别,完全服从ACID原则,完全避免了脏读,幻读和不可重复读,因为所有的事务依次逐个执行
实战演示
读未提交Read UnCommitted
建立AB两个查询
两个查询都设置隔离级别为Read Uncommitted读未提交
-- A事务设置读未提交
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
select * from test_count;
-- B事务设置读未提交
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
select * from test_count;
A事务修改id为1的数据
-- A事务设置读未提交
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
START TRANSACTION;
select * from test_count;
UPDATE test_count set count = 100 where id = 1
B事务读取到id 为1 的数据为100
A 事务回滚
-- -- -- A事务设置读未提交
-- SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
--
-- START TRANSACTION;
-- select * from test_count;
-- UPDATE test_count set count = 1001 where id = 1
--
ROLLBACK
B事务读取到了中间值为100 的错误数据,产生脏读
读提交Read Committed
-- -- A事务设置读提交
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
START TRANSACTION;
select * from test_count;
UPDATE test_count set count = 1001 where id = 1
select * from test_count;
-- B事务设置读提交
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
select * from test_count
结果发现A事务一直读取的是脏数据1001,而B事务不会脏读
-- -- A事务设置读提交
-- SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
--
-- START TRANSACTION;
-- UPDATE test_count set count = 1001 where id = 1;
-- select * from test_count;
COMMIT
一旦A提交了事务,那么B是可以读取到1001的,那么B就产生了不可重复读。
Repeatable Read 可重复读
-- -- A事务设置可重复读
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
UPDATE test_count set count = 1004 where id = 1;
select * from test_count;
-- COMMIT
-- -- B事务设置可重复读
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
select * from test_count;
-- COMMIT
B事务再未提交的前提下,查询的数据都是一致的,可重复读消失
幻读存在
-- -- A事务设置可重复读
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
INSERT into test_count VALUES(5,10001);
select * from test_count;
COMMIT
-- -- B事务设置可重复读
-- SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- START TRANSACTION;
-- select * from test_count;
INSERT into test_count VALUE(6,1002);
-- COMMIT
发现B事务查询的时候查询不出id 为6的 数据,但是B事务插入却失败,说明存在幻读