事务及四大特性
- 什么是事务
简单的说, 事务: 就是将一堆的SQL语句的执行, 绑定在一起, 要么全部执行成功, 要么全部执行失败!!
以转账为例: 现有A, B两个账户, 金额都是1000元, 现在A要转账给B 100元:
update acc set money=money-100 where name=’A’;
update acc set money=money+100 where name=’B’;
如果A账户减去100元执行成功了, 但是B加上100元(因为一些设备故障导致)失败了, 此时A+B的总金额比转账之前少了100??
事实上, 这种事情在现实生活中是不会出现的.
因为, 转账操作中的所有SQL语句是在一个事务中的, 要么全部执行成功, 要么全部执行失败, 如果B加上100执行失败了, A减去100必然也会失败!!
2 .事务的四大特性
1.原子性: 事务中的所有操作都是不可再分割的原子单位, 要么全成功, 要么全失败!!
2.一致性: 事务前后的业务数据总和是保持一致的, 比如转账之前, A和B的账号金额之和是2000元, 无论A给B转账多少钱, 无论成功与否, 转账之后的A和B的账号金额之和也必然是2000元
3.隔离性: 两个事务的操作是完全隔离的, 一个事务不能查看到另外一个事务正在执行的状态, 比如A转账给B账号, A刚减去100元, 此时会不会被另外一个事务查看到这个状态??? 答案是不会的, 另外一个事务, 要么查看转账操作进行之前的状态, 要么查看到转账操作结束之后的状态, 不可能看到中间的状态, 因为事务之间是隔离开来的!!
4.持久性: 只有在事务提交成功后, 事务中对数据的修改才会真正的保存到数据库中, 否则就是撤销之前的操作.
3. MySQL中的事务
在默认情况下,MySQL每执行一条SQL语句,都是一个单独的事务。如果需要在一个事务中包含多条SQL语句,那么需要开启事务和结束事务。
开启事务:start transaction;
结束事务:commit(提交事务)或rollback(回滚事务)。
在执行SQL语句之前,先执行strat transaction,这就开启了一个事务(事务的起点),然后可以去执行多条SQL语句,最后要结束事务,commit表示提交,即事务中的多条SQL语句所做出的影响会持久化到数据库中。或者rollback,表示回滚,即回滚到事务的起点,之前做的所有操作都被撤消了!
4.事务并发读问题
多个事务对相同的数据同时进行操作,这叫做事务并发。
在事务并发时,如果没有采取必要的隔离措施,可能会导致各种并发问题,破坏数据的完整性等。这些问题中,其中有三类是读问题,分别是:脏读、不可重复读、幻读。
(1)脏读(dirty read):读到另一个事务的未提交更新数据,即读取到了脏数据;
例如:A给B转账100元但未提交事务,在B查询后,A做了回滚操作,那么B查询到了A未提交的数据,就称之为脏读。
事务1:
A-100 900
B+100 1100
没有提交事务(数据并没有真正的保存到数据库)
回滚
事务2:
B 1100
(2)不可重复读(unrepeatable read):对同一记录的两次读取不一致,因为另一事务对该记录做了修改(是针对修改操作)
例如:在事务1中,前后两次查询A账户的金额,在两次查询之间,另一事物2对A账户的金额做了修改,此种情况可能会导致事务1中,前后两次查询的结果不一致。这就是不可重复读.
事务1:
查询1: A 1000
查询2: A 900
事务2:
修改: A 900
提交了事务
(3)幻读(虚读)(phantom read):对同一张表的两次查询不一致,因为另一事务插入了一条记录(是针对插入或删除操作);
事务1:
Select * from acc where id=3;
插入: 插入失败了…
事务2:
Insert into acc value(3, ‘c’, 1000);
注意:mysql默认的是不允许出现脏读和不可重复读,所以在下面演示之前需要设置mysql允许出现脏读、不可重复读等。
set tx_isolation=‘read-uncommitted’;
5 事务隔离级别
事务隔离级别分四个等级,在相同数据环境下,对数据执行相同的操作,设置不同的隔离级别,可能导致不同的结果。不同事务隔离级别能够解决的数据并发问题的能力也是不同的。
set tx_isolation=‘read-uncommitted’;
1、READ UNCOMMITTED(读未提交数据)
安全级别最低, 可能出现任何事务并发问题(比如脏读、不可以重复读、幻读等)
性能最好(不使用!!)
2、READ COMMITTED(读已提交数据)(Oracle默认)
防止脏读,没有处理不可重复读,也没有处理幻读;
性能比REPEATABLE READ好
3、REPEATABLE READ(可重复读)(MySQL默认)
防止脏读和不可重复读,不能处理幻读问题;
性能比SERIALIZABLE好
4、SERIALIZABLE(串行化)
不会出现任何并发问题,因为它是对同一数据的访问是串行的,非并发访问的;
性能最差;
MySQL的默认隔离级别为REPEATABLE READ,即可以防止脏读和不可重复读