事务的主要目的,把数据库从一个一致的状态转移到另一个状态

ACID

  • 原子性,要么完全发生,要么不发生
  • 一致性,从一个一致的状态一致转变到另一个状态
  • 隔离性,事务提交前,其他事物察觉不到事务的影响
  • 持久性,一旦事务提交,是永久的

事务控制语句

oracle中没有"开始事务"语句,隐式开始于第一条修改数据的语句(第一条得到TX的语句)

发出COMMIT或者ROLLBACK显式结束四五

  • COMMIT
  • COMMIT WORK

二者是等效的,分布式事务中,对commit语句有扩充,允许注释标记commit,强制提交有异议的分布式事务

  • ROLLBACK,等价于ROLLBACk WORK,回滚结束事务,撤销任何没有提交的操作,通过读取存储在回滚段中的信息实现的,把数据库块恢复到事务前
  • SAVEPOINT,允许在事务中创建一个"标记点",单个事务可以有多个savepoint
  • ROLLBACK TO <SAVEPOINT>,回滚到事务标记点,不回滚标记点前面的工作

如果使用两条update语句,后边跟一个savepoint,然后两条delete,执行时发生错误,事务将回滚到savepoint命名的地方

  • SET TRANSACTION,允许设置不同的事务属性,如隔离级别和是否只读或可读写,也可以使用此语句指示事务使用某个特定的回滚段

 savepoint在Oracle内部使用最频繁,也能在应用程序中找到使用它的地方

完整性约束和事务

完整性约束检查在整条SQL语句执行完以后立即进行检查,而不是在整个存储过程中执行完后进行

从Oracle8开始,推迟约束检查

处理事务的不良习惯

面对更新多行任务,大多数程序员在循环中使用过程化方法,能逐行提交

  • 经常提交一些小事务比执行和提交一个大的要快,效率高
  • 没有足够的回滚段空间

SET TRANSACTION语句告诉事务使用巨大的回滚段,最后删掉回滚段,释放空间

JDBC会隐式提交,可以通过下面对连接对象的设置关闭自动提交

conn.setAutoCommit(false)

分布式事务

Oracle可以透明地处理分布式事务,关键是数据库链接

create synonym T for T@another_database;

由数据库链接ANOTHER_DATABASE定义的数据库实例的表T,隐藏了T是远程表的事实

可以像本地表一样访问表T,这样执行一个分布式事务和本地事务没有区别了

update local_table set x = 5;
update remote_table@another_database set y=10
commit;

Oracle使用2PC,两阶段提交协议来完成

  • 允许修改影响多个原子性提交的数据库,在提交前尽可能尝试关闭分布式失败的窗口
  • 在多个数据库之间的2PC中,其中一个数据库会作为分布式事务的协调者,该site可以咨询其他site是否准备好提交
  • 其他真点回返回准备状态,有一个站点报告NO,整个事务回滚,都报告YES,协调者回广播信息,永久提交

2PC,试图尽量关闭多的错误窗口,但不能全部关闭,如果协调者广播提交,由于网络故障,自站点挂起,此时无法接收通知

子站点必须保持事务打开,等待站点1通知,RECO进程用来解决这个问题

带有force的commit和rollback也起作用

分布式事务的限制

  • 不能通过数据库链接使用COMMIT,只能从发起事务的站点提交
  • 不能通过数据库链接执行DDL
  • 不能通过数据库链接使用savepoint,即不能通过数据库链接使用任何事务控制语句

通过设置站点的提交点强度(一个init.ora参数),可以改变实际的提交站点

分布式事务中,提交点强度于服务器重要程度正相关

重做和回滚

insert into t(x,y) values (1,1);
update t set x = x+1 where x=1;
delete from t where x=2;

如果更新后系统出现故障会发什么什么

如果成功提交后会发生什么

如果回滚会发生什么

撤销包含许多信息,例如在X和Y的索引,它们的改变在回滚里未完成,撤销也存储在回滚段

  • 回滚段保存在表空间中,由重做日志保护
  • 对待回滚数据就像对待表数据或索引数据一样,回滚段的变化产生一些重做,被记录下来
  • 撤销数据添加到回滚段,就像其他数据一样,被缓存到缓存区高速缓存中,撤销也包含许多条信息

Oracle专家高级编程 第四章 事务_oracle

假设SGA出现故障,其中没有所需的信息,重启时,事务从没有发生,含有修改信息的块没有丢失,重做信息没有丢失

假设缓冲区高速缓存被填满,DBWR必须腾出空间,必须释放刚才修改的块

DBWR要求LGWR刷新保护数据库块的重做块,在DBWR写入要改变硬盘块之前需要释放重做日志缓冲区

Oracle专家高级编程 第四章 事务_oracle_02

当第三个块填满且有提交发生时,每隔3秒就会释放一块

块本身可能在硬盘上结束,也可能未结束

Oracle专家高级编程 第四章 事务_数据库_03

在块缓冲区高速缓存中有更多心的回滚段块,为了撤销更新,可以修改缓存中的数据库表和索引块

也产生了更多的重做日志缓冲区条目,一些在硬盘山,一些在缓存中

故障恢复,系统分两步进行

  • 前滚,把系统恢复到出现问题时的状态
  • 回滚没有提交的事务

回滚过程中,没有涉及到redo log,只有当恢复和归档时才读取重做日志

Commit,Oracle将重做日志缓冲区刷新到硬盘

Oracle专家高级编程 第四章 事务_回滚_04

修改的块在缓冲区高速缓存中,一些可能刷新到了硬盘

重放该事务所需的全部重做(redo),信息安全地放在硬盘上,永久改变

undo log将被悬挂,知道回滚段反转并且重用这些块

论读书
睁开眼,书在面前 闭上眼,书在心里