《Oracle 9i&10g 编程艺术》读书笔记——事务
1、 Oracle并发控制的基础,是多版本。
2、 Oracle保证读一致性,并且永远都不会脏读(即读其他事务的未提交数据)。Oracle查询得到的结果集肯定是某个时间点的当前结果集:
i. 游标(cursor)打开时的时间点。
ii. 语句开始执行时的时间点。Oracle总是保证语句级的读一致性。
iii. 查询所属事务开始的时间点。当事务隔离级别是serializable或read only时。
3、 Oracle中的查询,不会被写入阻塞,Oracle中没有读共享锁。并且Oracle的非阻塞读,不是以脏读为代价的:Oracle永远都不会脏读(第2条)。
4、 Oracle提供了read committed、serializable和read only三种事务隔离级别。
i. Oracle不需要read uncommited级别,Oracle不允许脏读。因为Oracle不需要脏读,就完全可以得到脏读的好处(即无阻塞读)。
ii. read committed是oracle的默认隔离级别,也是最常用的隔离级别。SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
iii. Oracle没有提供read repeatable隔离级别。
1. Oracle不使用共享读锁就保证了读一致性,更具并发性。
2. Oracle在非serializable和read only隔离级别下,没法保证不产生丢失更新。需要采用锁定来解决。(第5条)
iv. Oracle实现serializable隔离级别,就是把通常在语句级得到的读一致性扩展到事务级。Oracle采用了一种乐观的方法来实现serializable隔离级别,它认为本事务想要更新的数据不会被其他事务所更新。如果被更新了,Oracle就会产生ORA-08117错误。
v. read only隔离级别就是只读的serializable隔离级别。用于为报表查询需求提供支持。在serializable和read only隔离级别中,如果重建数据所需的undo信息已经被回绕而不存在了,则会产生ORA-1555错误。
5、 Oracle的多版本读一致性,需要使用锁定来解决顺序读问题。
i. 悲观锁定:仅用于有状态或有连接环境。select … for update [nowait]。如果指定nowait,则如果其他事务正在更新或已经更新了这一行,则会产生ORA-00054错误;如果不指定nowait,则会一直等待下去。
ii. 乐观锁定:
1. 乐观锁定,如果发现数据已经被修改,那么要根据实际业务需求,来采取措施:
a) 获取新值,重新开始。
b) 根据业务规则解决更新冲突,试图合并两个更新的值。
2. 实现乐观锁定的方法:更新时,除了主键作为条件,另外增加一个条件。判断更新行数,如果是0行,说明数据已经改变。
a) 保存所有字段的旧值,作为更新条件。注意NULL值的判断。最简单的方法,不需要额外增加列。
b) 增加一个版本列,每次更新加1。适用于非10g的新表。
c) 增加一个时间戳列(TIMESTAMP),为最后一次更新时间。如果这个时间戳没有业务意义,建议用存储过程封装更新。适用于非10g的新表,并且可以获得得到最后一次更新时间的额外好处。
d) 使用所有字段校验和的旧值。不需要额外增加列,但是计算大字段时性能低下。
e) 使用Oracle 10g新提供的ORA_ROWSCN。为了避免“假报警”,需要带上ROWDEPENDENCIES重建数据库表。不需要额外增加列,轻量级。
6、 Oralce的多版本读一致性,可能造成小的“热表”上的大量IO。方法就是减少事务执行时间。运行的时间越长,也就需要更多的IO来读取undo中的旧数据,这是一个恶性循环。
7、 写阻塞:
i. 两个会话同时插入(insert)一行,主键或有唯一约束的列值相同。通过使用序列(sequence)产生主键,避免了一半问题。
ii. 如果update或delete产生阻塞,则说明程序可能丢失问题的BUG。
8、 写一致性:为了保证写一致性,Oracle可能会悄悄的回滚更新,并重新启动。这会导致BEFORE触发器执行两次。方法就是不在BEFORE触发器中使用自治事务,和执行非事务性语句。
9、 死锁:Oracle极少出现死锁。检测到死锁会产生ORA-00060错误。
10、 Oracle的约束,可以设置为deferrable。这样,可以设置约束为延迟状态(set constraint 约束名 deferred/immediate),来允许事务过程中的暂时违反约束。如外键的级联更新。
11、 在Oracle中,每个事务都应该只在必要时才提交,而在此之前不能提交。事务的大小要根据需求而定。锁、阻塞等问题并不是决定事务大小的关键,数据完整性才是确定事务大小的根本。
12、 rollback会做大量的工作,与rollback相比,commit完成的工作非常少。除非不得已,否则不希望回滚。常识是:既然不想commit,又何苦去做所有这些工作。