参考资料:
事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。
以第一个DML语句的执行作为开始
以下面的其中之一作为结束:
当多个会话同时访问(操作)相同的数据时,将会出现一些意想不到的结果。包括:
ANSI定义的事务的隔离等级:
事务隔离等级 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
Read uncommited(读未提交的) | Y | Y | Y |
Read commited(读提交的) | N | Y | Y |
Repeatable read | N | N | Y |
Serializable | N | N | N |
Oracle定义的事务隔离等级:
事务隔离等级 | 影响 |
---|---|
Read commited | Oracle默认的隔离等级,对一条SQL,可以保证数据的一致性,对于一个事务,无法做到repeatable read。 |
Serializable | 只能看到事务开始时所有提交的改变以及自身的改变 |
Read-only | 只能看到事务开始时所有提交的改变,自身不允许DML操作 |
Oracle的锁定机制
Oracle和Sql Server锁的区别
Sql Server | Oracle |
---|---|
并发和读一致性不可兼得,必须牺牲一方 | 可兼得 |
因为锁实现方式,事务代价昂贵 | 没有真正的锁,事务没有资源代价 |
提倡尽快提交 | 主张按照业务需求确定事务边界 |
通过在事务中间设置检查点,可以更加精细的控制事务,防止一部分错误操作导致整个事务重新运行。演示如下:
SQL> create table t(id int);
表已创建。
SQL> insert into t values(1);
已创建 1 行。
SQL> savepoint s1;
保存点已创建。
SQL> select * from t;
ID
----------
1
SQL> update t set id=2;
已更新 1 行。
SQL> savepoint s2;
保存点已创建。
SQL> select * from t;
ID
----------
2
SQL> rollback to s1;
回退已完成。
SQL> select * from t;
ID
----------
1
一旦返回到保存点s1之后s2就失去了效果,因为已经回到s1了,这时候s2还不存在。
自治事务允许在一个事务中存在独立的事务,它的操作不会对当前事务产生影响。
语法:
pragma autonomous_transaction
关于自治事务的使用可以参考:ORACLE中的自治事务
实验演示如下:(演示用例来自参考资料Oracle中的自治事务)
首先是不使用自治事务
SQL> create table msg (msg varchar2(120));
SQL> set serveroutput on
SQL> declare
2 cnt number := -1; --} Global variables
3 procedure local is
4 begin
5 select count(*) into cnt from msg;
6 dbms_output.put_line('local: # of rows is '||cnt);
7
8 insert into msg values ('New Record');
9 commit;
10 end;
11 begin
12 delete from msg ;
13 commit;
14 insert into msg values ('Row 1');
15 local;
16 select count(*) into cnt from msg;
17 dbms_output.put_line('main: # of rows is '||cnt);
18 rollback;
19
20 local;
21 insert into msg values ('Row 2');
22 commit;
23
24 local;
25 select count(*) into cnt from msg;
26 dbms_output.put_line('main: # of rows is '||cnt);
27 end;
28 /
local: # of rows is 1 -> 子程序local中可以’看到’主匿名块中的uncommitted记录
main: # of rows is 2 -> 主匿名块可以’看到’2条记录(它们都是被local commit掉的)
local: # of rows is 2 -> 子程序local首先’看到’2条记录,然后又commit了第三条记录
local: # of rows is 4 -> 子程序local又’看到’了新增加的记录(它们都是被local commit掉的),然后又commit了第五条记录
main: # of rows is 5 -> 主匿名块最后’看到’了所有的记录.
PL/SQL 过程已成功完成。
从这个例子中,我们看到COMMIT和ROLLBACK的位置无论是在主匿名块中或者在子程序中,都会影响到整个当前事务.
现在如果将procedure local改成自治事务,在procedure local后面加上:
pragma AUTONOMOUS_TRANSACTION;
效果如下:
SQL> declare
2 cnt number := -1; --} Global variables
3 procedure local is
4 pragma AUTONOMOUS_TRANSACTION;
5 begin
6 select count(*) into cnt from msg;
7 dbms_output.put_line('local: # of rows is '||cnt);
8
9 insert into msg values ('New Record');
10 commit;
11 end;
12 begin
13 delete from msg ;
14 commit;
15 insert into msg values ('Row 1');
16 local;
17 select count(*) into cnt from msg;
18 dbms_output.put_line('main: # of rows is '||cnt);
19 rollback;
20
21 local;
22 insert into msg values ('Row 2');
23 commit;
24
25 local;
26 select count(*) into cnt from msg;
27 dbms_output.put_line('main: # of rows is '||cnt);
28 end;
29 /
local: # of rows is 0 -> 子程序local中无法可以’看到’主匿名块中的uncommitted记录 (因为它是独立的)
main: # of rows is 2 -> 主匿名块可以’看到’2条记录,但只有一条是被commited.
local: # of rows is 1 -> 子程序local中可以’看到’它前一次commit的记录,但是主匿名块中的记录已经被提前rollback了
local: # of rows is 3 -> 子程序local 中可以’看到’3条记录包括主匿名块commit的记录
main: # of rows is 4 ->主匿名块最后’看到’了所有的记录.
PL/SQL 过程已成功完成。
角色 | 描述 |
---|---|
client | 调用其它数据库信息的节点 |
database | 接受来自其它节点请求的节点 |
Global coordinate | 发起分布式事务的节点(全局调度者) |
Local coordinate | 处理本地事务,并和其它节点通信的节点(本地调度者) |
Commit point site | 被global coordinate指定第一个提交或回滚事务的节点 |
commit Point Strength
Oracle选取Commit Point Strength(相当于权重)最大的数据库作为Commit point。
2PC-two phase commit
准备阶段prepare phase
为了完成准备阶段,除了commit point机器外,其它的数据库机器按照以下步骤执行:
提交阶段commit phase
提交阶段按下面的步骤进行:
分布式事务的结束就是全局协调器和commit point两者之间释放资源的顺序。
###分布式事务的安全性
2PC是否真的可以保证分布式事务的一致性?
关于CAP理论可以参见:CAP理论