数据库版本

SYS@LEO1>select * from v$version;

BANNER

--------------------------------------------------------------------------------

Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production

PL/SQL Release 11.2.0.1.0 - Production

CORE    11.2.0.1.0      Production

TNS for Linux: Version 11.2.0.1.0 - Production

NLSRTL Version 11.2.0.1.0 - Production

事务那些事儿()

1.事务:事务可以理解为一系列动作的逻辑单位,我们把这一系列动作叫做一个事务。这一系列动作要持续完成的,中间不可以断。

2.事务与锁的关系:事务的并发是由锁来控制的(同一时间只允许一个会话来操作),锁是数据库并发操作中最常见的保护机制。不同的数据库锁机制也有很大差异。

Oracle与SQL server的区别

Oracle                                              SQL server

可以实现读/写互不阻塞,利用undo实现读会阻塞写,写也会阻塞读,用查询锁定实现

锁作为数据块一种属性存在,没有锁管理器使用锁管理器控制事务并发,代价昂贵

主张按照业务需求确定事务边界提倡尽快提交事务

3.事务控制:commit&rollback都是一个事务的结束

我们可以在一个事务生命周期的一半设置一个save point,遇到问题我们可以回退到这个保存点而不需要把事务全部回退,从而更加精细化的控制事务。

4.分布式事务:

举一个例子,说明save point的用处,给出SQL演示。

保存点save point:我们可以理解为放置在事务中的一个“标签点”,防止一部分操作错误导致整个事务重新执行。我们只需要回退到这个标签点的位置继续重做后面的操作即可。

实例

铃铃铃。。。下课铃响了,刚刚上完tiger的“大数据探索之旅”课程,tiger老师在下课后给大家留了一道小作业,现在想把作业成绩给大家登记下来。

LEO1@LEO1>drop table leo1 purge;                   清空环境

Table dropped.

LEO1@LEO1>create table leo1 (x int);                  创建成绩表

Table created.

LEO1@LEO1>insert into leo1 values(10);                学号1的同学成绩为10

1 row created.

LEO1@LEO1>select * from leo1;

X

----------

10

LEO1@LEO1>savepoint leo_1;                        为了防止误操作,我们随机做几个保存点

Savepoint created.

LEO1@LEO1>insert into leo1 values(20);                学号2的同学成绩为20

1 row created.

LEO1@LEO1>insert into leo1 values(30);                学号3的同学成绩为30

1 row created.

LEO1@LEO1>select * from leo1;                       成绩表中有3条记录

X

----------

10

20

30

LEO1@LEO1>savepoint leo_2;                         保存点2

Savepoint created.

突然发现把学号2和学号3的成绩登记错了,现在只想回退到学号1登记之后的位置,如果全回退所有的工作都白做了,聪明的tiger老师不会这么干的,此时我们标记的保存点派上用场了,我们只需回退到leo_1即可。

LEO1@LEO1>rollback to leo_1;

Rollback complete.

这里说明一点,虽说回退到了leo_1保存点,但这个事务还没有顺利结束,其他会话不可见,只有commit之后才表示事务完整结束。

LEO1@LEO1>select * from leo1;                       ok此时继续重做后面的操作就完事大吉

X

----------

10

LEO1@LEO1>commit;

Commit complete.

写一个用于审计的触发器,利用自治事务技术。

自治事务:一个事务中嵌套另一个事务,彼此是相互独立的,互不干涉。

应用场合:需要独立处理一件事情,例如独立审计过程。

实例

我们经常会在淘宝上买东西,渐渐我们自己也想开个小铺,我们有一个产品明细表product,还有一张审计表product_audit。审计表里记录着我们产品的变化情况(我们在审计的过程中使用自治事务技术),我们只需要知道产品还剩余多少即可。

Product表

LEO1@LEO1>create table product (id int,name varchar2(20),num int,cost int);

Table created.

LEO1@LEO1>insert into product values(1,'apple',10,10);            插入5条记录

1 row created.

LEO1@LEO1>insert into product values(2,'orange',20,20);

1 row created.

LEO1@LEO1>insert into product values(3,'banana',30,30);

1 row created.

LEO1@LEO1>insert into product values(4,'mango',40,40);

1 row created.

LEO1@LEO1>insert into product values(5,'KFC',50,50);

1 row created.

LEO1@LEO1>commit;

Commit complete.

LEO1@LEO1>select * from product;

ID NAME                        NUM       COST

---------- -------------------- ---------- ----------

1 apple                        10         10

2 orange                       20         20

3 banana                       30         30

4 mango                        40         40

5 KFC                          50         50

Product_audit表

LEO1@LEO1>create table product_audit (id int,name varchar2(20),remain_num int);

Table created.

创建审计触发器tib_product,当product表有update动作之后被触发,会把剩余数记录到product_audit表里

LEO1@LEO1>create or replace trigger tib_product after update on product for each row

declare

pragma autonomous_transaction;        这句话声明下面的事务是一个自治事务,独立存在的

tib_id         number;

tib_name       varchar2(20);

tib_remain_num number;

begin

tib_id :=:old.id;

tib_name :=:old.name;

tib_remain_num :=:new.num;

insert into product_audit values (tib_id,tib_name,tib_remain_num);

commit;

end;

/

2    3    4    5    6    7    8    9   10   11   12   13   14

Trigger created.

每个产品我们都卖了一半,更新5条记录

LEO1@LEO1>update product set num=5  where name='apple';

1 row updated.

LEO1@LEO1>update product set num=10 where name='orange';

1 row updated.

LEO1@LEO1>update product set num=15 where name='banana';

1 row updated.

LEO1@LEO1>update product set num=20 where name='mango';

1 row updated.

LEO1@LEO1>update product set num=25 where name='KFC';

1 row updated.

LEO1@LEO1>select * from product;

ID NAME                        NUM       COST

---------- -------------------- ---------- ----------

1 apple                         5         10

2 orange                       10         20

3 banana                       15         30

4 mango                        20         40

5 KFC                          25         50

此时我们把改变的数据进行回滚,看看审计表有没有影响

LEO1@LEO1>select * from product;                           产品明细表成功回滚,事务结束

ID NAME                        NUM       COST

---------- -------------------- ---------- ----------

1 apple                        10         10

2 orange                       20         20

3 banana                       30         30

4 mango                        40         40

5 KFC                          50         50

这时我们再看看审计表有没有记录着产品的剩余情况

LEO1@LEO1>select * from product_audit;               good很好,完全记录下来了

ID NAME                 REMAIN_NUM

---------- -------------------- ----------

1 apple                         5

2 orange                       10

3 banana                       15

4 mango                        20

5 KFC                          25

我们登陆一个新会话,如果新会话也可以正常访问到product_audit表说明我们设计的自治事务完整结束

LEO1@LEO1>select distinct sid from v$mystat;

SID

-----------------

142

LEO1@LEO1>select * from product_audit;                good可以正常看到测试非常成功

ID NAME                 REMAIN_NUM

---------- -------------------- ----------

1 apple                         5

2 orange                       10

3 banana                       15

4 mango                        20

5 KFC                          25

小结:通过上面的实验我们可以感受到自治事务在某些场景下可以给我们带来很大方便,通过自治事务我们可以很好的实现事务隔离。

请画出一个分布式事务操作的原理图。

分布式事务:所谓分布式事务就是发生在多台数据库之间的事务操作,它们通过dblink实现事务处理。分布式事务要比单机事务复杂的多,其中涉及到网络问题操作系统问题数据库问题等等。具体操作原理请参考下图所示

下方是三个数据库A B C,它们之间是通过dblink连接进行分布式事务操作。

转://Oracle 事务探索与实例(二)-LMLPHP

分布式事务之术语

Client:访问其他数据库的节点

Database:接收来自其他数据库访问的节点,例如 A库->访问->B库,那么A就是client端,B就是database端

Global coordinator:发起分布式事务的节点

Local coordinator:处理本地事务的节点

Commit point:被global coordinator指定为首先提交or回滚的事务节点,就是第一个提交的节点叫提交点,其他节点按顺序完成提交。

数据库集群中每个库都有一个commit_point_strength提交点权重参数,Oracle选取权重最大的数据库为集群提交点,如果权重都一样,Oracle随机选择提交点。

SYS@base> show parameter commit_point

NAME                                 TYPE        VALUE

------------------------------------ ----------- ------------------------------

commit_point_strength                integer     1

2PC(two phase commit)2阶段提交:第一阶段叫prepare phase准备阶段,第二阶段叫commit phase提交阶段。如果是本地事务就一阶段直接提交,如果是分布式事务就采取二阶段提交。下面解释一下这两个阶段的具体内容

Prepare phase 准备阶段

(1)每个节点检查自己是否被其他节点所引用,如果有就通知这些节点准备提交。

(2)每个节点检查自己运行的事务,看看有没有修改数据的操作,如果没有则跳过后面步骤直接返回一个只读信号给gc全局协调进程。

(3)如果事务需要修改数据,就分配相应的资源给事务并记录redo信息,这些redo信息保证事务失败后的回滚。

(4)当上面的工作都成功后,给gc全局协调进程返回准备就绪的信号,反之则返回失败的信号。

Commit phase 提交阶段

(1)首先gc全局协调器通知提交点进行提交,完成后告知gc。

(2)gc全局协调器再通知其他数据库节点进行提交并记录redo信息,完成后告知gc

(3)当gc得知所有分布式事务提交完成后,告知提交点数据库释放事务相关资源,完成后告知gc

(4)gc全局协调器释放自己的资源

(5)分布式事务结束

请分析分布式事务为什么无法保证事务最终的一致?请分析可能出现的问题以及解决方法。

这个论点已经由CAP理论证实了

CAP 理论断言任何基于网络的数据共享系统,最多只能满足数据一致性、高可用性、分区容错性三点中的两点。

CAP理论图示

转://Oracle 事务探索与实例(二)-LMLPHP

AP架构实例:一个购物网站,如果允许系统实现高可用和分区容错性,当集群中某一节点出现故障的时候,就要暂时失去数据一致性,等待故障节点恢复正常,然后满足数据的最终一致性,允许经过一个时间窗口后在一致。

解决方法:对于事务性很强的关系型数据库而言,当发生一致性失败后,整个分布式事务都进行回滚,回退到初始状态,当故障解决后在运行事务操作。

我们在现实生活中常常会用“QQ传送文件”,当你发送一个文件传到一半的时候网络断了,这时就出现了数据不一致性现象,传送事务没有做完,通常QQ会选择放弃数据的一致性保证QQ程序可用性,等待网络恢复后继续完成事务。这里面QQ应用了上面提到的“保存点save point技术”实现断点续传功能,很好的解决了这个问题。

CA架构实例:中国人民银行的网上征信系统,必须满足一致性和高可用性,牺牲分区容错性,如果某个节点出现故障,断开网络连接,事务全部回退,暂停业务进行维修。

CP架构实例:某大学的图书馆系统,借还数据要保持一致,当有节点故障的时候,整个集群就会停止,维修后继续使用。

保存点自治事务分布式事务  CAP   数据一致性

05-08 15:24