- 事务的概念
1、 事务可以看作是由对数据库的若干操作组成的一个单元,这个单元是一个整体,该整体具有高度集体责任感、荣誉感,执行操作时要么都成功,要么都失败,从而保证数据满足一致性的要求;
2、 事务处理是所有大型数据库产品的一个关键问题,各数据库厂商都在这个方面花费了很大精力,不同的事务处理方式会导致数据库性能和功能上的巨大差异。
- 事务的例子
1、 银行转账:帐户A把一定数量的款项转到帐户B上,这个操作包括两个步骤,一个是从帐户A上把存款减去一定数量,二是在帐户B上把存款加上相同的数 量。这两个步骤显然要么都完成,要么都取消,否则银行就会受损失。显然,这个转帐操作中的两个步骤就构成一个事务。
- 事务的特性
1、原子性(Atomicity):
中学的化学课上我们都知道,原子不具备分割性,所以事务的原子特性就是指操作要么都成功,要么都失败,不可分割;
2、一致性(Consistency):
个人理解,一致性的属性与原子性具有一定的相同点,比如操作都成功或都失败都是一致性的表现形式;
3、隔离性(Isolation):
指当前的事务与其他的事务是隔离的。比如用户A和B都在操作数据库中的同一对象,A进行的是插入表值得操作,B进行是查询表中列值得平均数,隔离就是不能因为A在不断地插入新值,而B就不能求平均值或者求出的平均值会因为A的插入而变化;另外,隔离机制还涉及到oracle的锁,后续详细分析。
4、持久性(Durability):
持久性是指事务提交(commit)或者回滚(rollback)的结果集确认固定化,简单理解为,提交或者回滚的结果不能改变了,影响是持久性的。
未结束的事务(事务过程没有处理完毕,正在执行中)在遇到断电或系统错误等故障,即使未结束的事务部分作用的结果已经写入内存,但数据库在下次自动启动时会回滚取消;相反,如果事务已经执行完毕,但是没有来得及写入内存,数据库在下次自动启动的时候,会通过事务日志中的记录进行“重做”,即把丢失的数据修改结果重新生成,并写入内存,从而保证结束事务对数据修改的永久化;
- 隔离标准
在SQL92标准中,事务隔离级别分为四种,分别为:Read Uncommitted、Read Committed(提交读)、Read Repeatable、Serializable(串行读),其中Read Uncommitted与Read Committed为语句级别的,而Read Repeatable与Serializable是针对事务级别的。
Oracle中只有两种隔离级别:Read Committed(提交读)、Serializable(串行读),前者属于语句级别,后者属于事务级别;
- READ COMMITED(提交读)
Oracle默认隔离级别;
每条语句都支持语句级读一致性;
不允许脏读(错读),但是可能会出现不可重复读和幻读的情况;
- SERIALIZABLE(串行读)
需要用户单独设置隔离级别,设置方式详情见第七章内容;
简单理解,在serializable模式下其他事务对同一对象的更新、删除、插入操作都不会影响本事务的select的查询结果,因为本事务中的数据是回滚段内的,只有本事务更DML操作才会影响本事务的查询结果。
serializable模式下不会出现脏读、不可重复读、幻读的情况;
注释:
脏读(错读):当前事务读取了其他事务还没有提交的结果;
不可重复读:其他事务执行更新操作导致当前事务重新查询时结果不一致;
幻读:与不可重复读类似,但是特指其他事务执行插入操作后导致当前事务重新查询时结果不一致;
两种隔离机制区别图:
模式名称 |
脏读(错读) |
不可重复读 |
幻读 |
READ COMMITED |
× |
√ |
√ |
SERIALIZABLE |
× |
× |
× |
- 隔离级别设置方式
方式一:
SET TRANSACTION ISOLATION LEVEL READ COMMITED;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
方式二:
ALTERSESSION SET ISOLATION_LEVEL=READ COMMITED;
ALTERSESSION SET ISOLATION_LEVEL=SERIALIZABLE;
关于两种设置方式的区别:
设置方式 |
起始生效时间 |
终止有效时间 |
备注说明 |
SET |
本命令执行完毕开始 |
一个事务提交或回滚 |
|
ALTER |
Select语句执行时 |
会话终止或关闭 |
推荐这种方式测试 |
- 关于串行隔离下的几种试验
试验开始前,我们需要搭建试验环境,准备两个sqlplus会话窗口A和B,下面是会话名设置方式:SETSQLPROMPT “A”; SET SQLPROMPT “B”;
我们需要创建一个test测试表,用作我们串行隔离机制试验
SQL>DROP TABLE test;
SQL> CREATE TABLE test (tnonumber(4));
SQL>INSERT INTO test VALUES(1);
SQL>INSERT INTO test VALUES(2);
然后设置串行隔离机制,为了试验方便,我们采用ALTER 方式进行设置
A和B会话都需要执行下面的语句:
ALTER SESSION SET ISOLATION_LEVEL=SERIALIZABLE;
试验一:更新已提交的插入(B比A早)
1、 会话B执行
SQL>INSERT INTO test VALUES(3);
插入完毕后,暂不COMMIT;
2、 切换至A会话执行
SQL>SELECT * FROMtest;
3、 切换至B会话执行COMMIT;
4、 切换至A会话执行
SQL>UPDATE test SET tno= tno +1(tno各自加1)
5、 A会话提示已更新2行;
6、 结论:成功,但是只更新回滚段内数据,不会发生数据丢失;
试验二:更新已提交的插入(A比B早)
1、 会话A执行
SQL>SELECT * FROMtest;
2、 切换至B会话执行
SQL>INSERT INTO test VALUES(3);
3、 B会话执行COMMIT;
4、 切换至A会话执行
SQL>UPDATE test SET tno= tno +1(tno各自加1)
5、 A会话提示:ORA-08177:无法连续访问此事务处理
6、 结论:失败,更新会导致数据丢失;
试验三:更新已提交的删除(B比A早)
1、 会话B执行
SQL>DELETE test WHERETNO=’2’;
删除完毕后,暂不COMMIT;
2、 切换至A会话执行
SQL>SELECT * FROM test;
3、 切换至B会话执行COMMIT;
4、 切换至A会话执行
SQL>UPDATE test SET tno= tno +1(tno各自加1)
5、 A会话提示:ORA-08177:无法连续访问此事务处理
6、结论:失败,更新会导致数据丢失;
试验四:更新已提交的删除(A比B早)
1、 会话A执行
SQL>SELECT * FROMtest;
2、会话B执行
SQL>DELETE test WHERETNO=’2’;
3、切换至B会话执行COMMIT;
4、切换至A会话执行
SQL>UPDATE test SET tno= tno +1(tno各自加1)
5、A会话提示:ORA-08177:无法连续访问此事务处理
6、结论:失败,更新会导致数据丢失;
- 九、关于一个会话窗口中同时存在两种方式的serializable设置
虽然实际环境中不用这样操作,但是这里的叙述是想告诉大家:如果真的有这种情况,那么一定是ALTER 在第一行,SET在第二行,否则报错。
因为SET这种设置方式一旦执行就开启了串行隔离机制,这种机制随着commit或者rollback命令而结束,所以串行事务开启后就不能再次使用ALTER 命令行方式进行设置;
相反,如果ALTER命令行方式是在第一个select命令执行时才开启隔离机制,所以再使用SET方式也是可以的。
最后还是需要告诉大家ALTER和SET起始生效范围