翻译自Dave Ruhde的Oracle Tips Session
一、相关名词解释
Concurrentcy(并发性):多个会话同时访问同一数据。
Consistency(一致性):在多个会话、事务或者SQL语句之间或者之内,数据一致性的情况。
Statement(语句):一个修改数据库数据的SQL命令。对数据库的修改可能提交也可能未提交。例如,SELECT, SELECT...FOR UPDATE, INSERT, UPDATE, DELETE等。
Session(会话):某个数据库用户通过一个外部程序与数据库服务器的一次连接。打开此会话的程序可以是用户输入的交互式的SQL语句,也可以是用其他语言开发出来的程序。
Transaction(事务):所有对数据库的修改都是通过事务完成的。一个事务中包括任意数量的SQL语句。一个事务以COMMIT或者ROLLBACK结束。若一个事务被提交,事务中对数据库所做的修改将会保存。如果一个事务被回滚,事务中对数据库所做的修改将被撤销。一个新的事务开始于一次会话的建立,结束于一个COMMIT或者ROLLBACK。
COMMIT(提交):把所有对数据库的修改都变成永久的。提交的动作在下面两种情况发生:
1)遇到COMMIT语句时。
2)应用程序结束,正常断开与oracle的会话时。
ROLLBACK(回滚):撤销所有未提交的事务。回滚以后,事务结束。回滚在下面情况发生:
1)遇到ROLLBACK语句时。
2)ORACLE因为下面情况异常终止时:
数据库或应用程序发生异常,应用程序非正常退出。
硬件错误或者操作系统错误导致应用程序退出。
网络连接错误,导致应用程序到ORACLE的连接中断。
ORACLE出错退出。
二、数据一致性
所有的ORACLE SQL语句都是针对某一时间点上的数据库数据的镜像来操作的,这个镜像在此特定的时间点上是一致的。这个一致性镜像从来不会反应出未被提交的改变,也就是说ORACLE不会进行“脏读”。[参考附注1]
默认情况下,一致性是语句级的,而不是事务级的。SQL语句使用该语句开始时那一时刻的数据库数据的镜像,而不是事务开始那一时刻的镜像。一个事务中的每一个语句维护本语句镜像的一致性。
图1中Session 2的第二个select语句没有看到Session 1对数据库的修改,因为在Session 2的第二个select语句开始的时刻,Session 1的update语句还没有提交。
图1 语句级的数据一致性
图2 的情况叫做“Phantom read”。Session 1已经删除了一行,但是Sessin 2并有看到它,因为delete语句没有在Session 2的select语句之前提交。
图2 Phantom read
例外的情况:SQL语句能看到“未被提交的对数据库的修改”,但仅限于这个修改发生在同一个事务中。简单的说,“未被提交的修改”在另外的会话中是不可见的,只有在同一个事务中才是可见的。
图3,第二个SELECT语句看到了本事务中的对数据库的修改,虽然这个修改尚未COMMIT,因为在同一个事务中,仍然是可见的。
图3 本事务中的修改
三、READ-ONLY 事务
在只读事务中,事务里的所有SQL语句眼中的一致性数据镜像(consistent data image)都是开始于事务开始那一时刻的,而不是SQL语句开始那一时刻的。在只读事务中,仅仅允许出现SELECT语句。例如:Session 2中的第二个SELECT语句将看不到Session 1中的修改,即使Session 1的事务在Session 2中的第二个SELECT语句以前已经提交。
图4 READ-ONLY事务
四、关于too old error
ORACLE 是通过什么办法向用户SQL呈现出一致性的数据镜像呢?答案就是通过对未提交的事务中的change进行undo。这些需要被undo的数据就被存放在回滚段(ROLLBACK SEGMENTS)中。若是回滚段的空间不足,那么那些用于重建一致性镜像的数据就会被覆盖掉,这时候就会出现错误:"snapshot too old (rollback segment too small)" error.
DBA应该想办法避免这种情况的发生,因此,如果一个应用程序预计会在出现大量update的同时,又有大量select查询的情况,(比如我们的选课系统)开发人员应该联系DBA来评估一下ROLLBACK SEGMENTS的合理使用。
图5 snapshot too old
五、数据并发
Oracle locks data minimally at the row level.
Readers donot lock writers
Readers donot lock readers.
SELECT ….FOR UPDATE behaves as a writer.
Writers only block writers trying to write the same row. Oracle locks at the row level and does not escalate locks
附注1:All Oracle SQL statements ALWAYS work with a image of data that is consistent to a single point-in-time. The consistent image consists of all changes and only changes COMMITTED before the point-in-time of the image.
The consistent image nevers shows changes that have not been committed to the database. Oracle never performs a "dirty read"