数据库---事务(Transaction)
一、概述
事务(Transaction)是一个操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单元,是数据库环境中的逻辑工作单元,事务是为了保证数据库的完整性
事务的开始:
在oracle中没有事务开始的语句,一个transaction起始于一条DML(insert、delete、update)语句。
mysql中使用 start transaction; 语句进行开启事务
事务的结束:
1、显示的执行commit语句提交操作 或者 rollback语句(将数据恢复到上一个状态)
2、自动提交,但一般情况下要将自动提交进行关闭,效率太低
3、用户关闭会话之后,会自动提交事务
4、系统崩溃或者断电的时候会回滚事务,也就是将数据恢复到上一个状态
5、执行DDL(create、alter、drop)语句事务自动提交
二、事务的特性(ACID)
- 原子性(Atomicity)
一个事务要么完整执行,要么就不执行。工作单元中每项任务都必须正确执行,如果有任意一个任务执行失败,则整个工作单元或事务都会被终止,即此前对数据所作的任务修改都将被撤销。如果所有任务都被成功执行,事务会被提交,即对数据所作的修改将会是永久性的。
- 一致性(Consistency)
一致性表达了底层数据存储的完整性,他必须由事务系统和应用开发人员共同来保证。
事务系统通过保证事务的原子性、隔离性、持久性来满足这一要求;应用开发人员则需要保证数据库有适当的约束(主键、引用完整性等),并且工作单元中所实现的业务逻辑不会导致数据的不一致(即数据预期所表述的现实业务情况不一致)。
当经过N多个操作之后,数据的状态不会改变(比如转账)。从一个一致性状态到另一个一致性状态,也就是说数据不可以发生错乱
- 隔离性(Isolation)
隔离性意味着事务必须在不干扰其他进程或者事务的前提下独立执行。
换而言之,在事务或者工作单元执行完毕之前,其所访问的数据不能受系统其他事务的影响。
严格的隔离性会导致效率降低,在某些情况下为了提高程序的效率,需要降低事务的隔离级别。
- 持久性(Durability)
持久性表示在某个事务的执行过程中,对数据所作的改动都必须在事务成功结束前保存至物理介质中。这样可以保证所作的修改在任何系统瘫痪时不至于丢失。
三、准备测试数据
CREATE TABLE trans ( id INT PRIMARY KEY, username VARCHAR ( 20 )) ENGINE = INNODB;
--插入数据 INSERT INTO trans VALUES (1,'zhangsan'); INSERT INTO trans VALUES (2,'lisi'); INSERT INTO trans VALUES (3,'wangwu'); COMMIT;
-- 查询mysql事务是否自动提交 select @@autocommit; -- 如果显示1 表示为开启自动提交 -- 如果显示0 表示为关闭自动提交
set autocommit=0;
四、事务隔离级别
- 读未提交(Read Uncommitted)
- 读已提交(Read Committed)
- 可重复读 (Repeated Read)
- 串行化 (Serializable)
会产生数据不一致的影响:
- 脏读
- 不可重复读
- 幻读
五、隔离级别:读未提交(脏读)
开启mysql的两个会话窗口进行模拟
-- 分别在A、B两个窗口执行设置当前会话的隔离级别 set session transaction isolation level read uncommitted; A:start transaction; A:select * from trans; B:start transaction; B:select * from trans;
执行完上述指令后,A、B窗口数据查询一致
A:update trans set username='han.sun'; A:selecet * from trans --读取的结果"han.sun"。 产生脏读,因为A事务并没有commit,读取到了不存在的数据 B:select * from trans; A:commit; --读取的数据是han.sun,因为A事务已经commit,数据永久的被修改 B:select * from trans;
六、隔离级别:读已提交(不可重复读)
开启mysql的两个会话窗口进行模拟
-- 设置A、B两个窗口会话隔离级别为 读已提交 set session transaction isolation level read committed; A:start transaction; A:select * from trans; B:start transaction; B:select * from trans; -- 初始化状态一致 A:update psn set name ='han.sun' where id = 1; A:select * from trans; B:select * from trans; --执行到此处发现两个窗口读取的数据不一致,B窗口中读取不到更新的数据
虽然解决了脏读问题,但是又产生了一个新的问题,不可重复读。
当A会话中的事务提交完成, B会话中的事务还未结束,但是B会话中读取的数据前后两次数据不一致现象。
A:commit; --读取到更新的数据 A:select * from trans; --也读取到更新的数据 B:select * from trans; --发现同一个事务中多次读取数据出现不一致的情况
七、隔离级别:可重复读(幻读)
开启mysql的两个会话窗口进行模拟
-- 设置A、B两个窗口会话隔离级别为 读已提交 set session transaction isolation level repeatable read; A:start transaction; A:select * from trans; B:start transaction; B:select * from trans; -- 初始化状态一致 A:update trans set username ='lisisi' where id=2; A:select * from trans; -- A事务内修改的数据已变化 B:select * from trans; -- B事务没有读取到修改的内容,说明避免了脏读 A:commit; A:select * from trans; -- A事务提交完成,修改的数据已永久保存 B:select * from trans; -- B会话中的事务还未提交,在同一个事务中前后两次读取的数据一致,不是A事务已提交修改后的数据,说明解决了同一个事务中不可重复读问题
上述说明当隔离级别为 :可重复读,解决了“脏读”、“不可重复读问题”;
但是同样可会带来新的问题-----“幻读”
八、隔离级别总结
隔离级别 | 脏读 | 不可重复读 | 幻读 |
读未提交 | √ | √ | √ |
读已提交 | √ | √ | |
可重复读 | √ | ||
串行化 |
1、对于不可重复读和幻读,单单从查询层面来说效果没有什么差别;
2、幻读是指在修改数据的时候产生幻读现象。
a、在此事务中没有查询到该数据,但在更新的时候却影响了多行数据;
b、在此事务中没有查询到该数据,但在新增的时候发现主键已存在无法插入;
c、在此事务中查询到了该数据,但在删除的时候发现数据无法删除,已经被别的事务进行删除了;只有提交事务才能发现数据已被删除。
3、不可重复读(是指在同一个事务中读取两次某个数据,但是前后两次数据不一致,针对修改操作)
4、脏读(即事务B读到了事务A还没有提交的数据。如果事务A对数据进行了更新,但是事务A并没有提交,但是事务B这个时候看到了事务A没有提交的更新。当事务A进行了回滚,那么刚刚事务B看到的数据就是脏数据。也就是脏读。)
大多数数据库默认的事务隔离级别是Read committed,比如Sql Server , Oracle。Mysql的默认隔离级别是Repeatable read。