参考资料:

Transactions

对于Oracle事务的总结


什么是事务?

事务(Transaction)是拜访并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务由事务开始(begin transaction)和事务完结(end transaction)之间执行的整体操作组成。

事务的属性-ACID

  • 原子性(Atomicity)-事务的原子性强调了一个事物是一个逻辑工作单元,是一个整体,是不可分割的。一个事务所蕴含的操作要么全副做,要不全副不做。
  • 一致性(Consistency)-一个事务执行一项数据库操作,事务使数据库从一种一致性的状态变换成另一种一致性状态。
  • 隔离性(Isolation)-在事务未提交前,它操作的数据,对其余用户不可见。
  • 持久性(Durability)-一旦事务胜利实现,该事务对数据库所施加的所有更新都是永恒的。

    • redo日志--提交的事务被永恒的记录到redo日志中。

<!--more-->

数据库事务的开始和完结

以第一个DML语句的执行作为开始

以上面的其中之一作为完结:

  • commit或rollback语句
  • DDL或DCL语句(主动提交)
  • 用户会话失常完结--commit
  • 零碎异样完毕--rollback

并发与数据的读取

当多个会话同时拜访(操作)雷同的数据时,将会呈现一些意想不到的后果。包含:

  • 脏读 --dirty reads

    一个事务读取了另一个事务未提交的数据,而这个数据是有可能回滚
  • 不可反复读 --non-repeatable reads

    在数据库拜访中,一个事务范畴内两个雷同的查问却返回了不同数据。这是因为查问时零碎中其余事务批改的提交而引起的。
  • 幻读 --Phantom(空幻的) reads

    事务1读取记录时事务2减少了记录并提交,事务1再次读取时能够看到事务2新增的记录。对事物1而言就如同呈现了幻觉一样。

事务的隔离等级

ANSI定义的事务的隔离等级:

事务隔离等级脏读不可反复读幻读
Read uncommited(读未提交的)YYY
Read commited(读提交的)NYY
Repeatable readNNY
SerializableNNN

Oracle定义的事务隔离等级:

事务隔离等级影响
Read commitedOracle默认的隔离等级,对一条SQL,能够保证数据的一致性,对于一个事务,无奈做到repeatable read。
Serializable只能看到事务开始时所有提交的扭转以及本身的扭转
Read-only只能看到事务开始时所有提交的扭转,本身不容许DML操作

事务的并发管制-锁

Oracle的锁定机制

  • Oracle尽可能的缩小锁定的应用
  • Oracle的读操作不会对表加锁,一些数据库会应用查问锁定(共享锁,排它锁)
  • Oracle通过回滚机制,保障读不会受到阻塞
  • Oracle没有锁管理器
  • Oracle中锁作为数据块的一种属性存在

Oracle和Sql Server锁的区别

Sql ServerOracle
并发和读一致性不可兼得,必须就义一方可兼得
因为锁实现形式,事务代价低廉没有真正的锁,事务没有资源代价
提倡尽快提交主张依照业务需要确定事务边界

事务的管制-savepoint

通过在事务两头设置检查点,能够更加精密的管制事务,避免一部分错误操作导致整个事务从新运行。演示如下:

SQL> create table t(id int);表已创立。SQL> insert into t values(1);已创立 1 行。SQL> savepoint s1;保留点已创立。SQL> select * from t;        ID----------         1SQL> update t set id=2;已更新 1 行。SQL> savepoint s2;保留点已创立。SQL> select * from t;        ID----------         2SQL> 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 onSQL> 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 过程已胜利实现。

分布式事务

  • 产生在多台数据库之间的事务。
  • 通过dblink形式进行事务处理。
  • 分布式事务要比单机事务要简单的多。
  • 可能的危险:软件,服务器,网络。

分布式事务的组成

角色形容
client调用其它数据库信息的节点
database承受来自其它节点申请的节点
Global coordinate发动分布式事务的节点(全局调度者)
Local coordinate解决本地事务,并和其它节点通信的节点(本地调度者)
Commit point site被global coordinate指定第一个提交或回滚事务的节点

commit Point Strength

Oracle选取Commit Point Strength(相当于权重)最大的数据库作为Commit point。

Oracle分布式事务的机制-两阶段提交

2PC-two phase commit

  • prepare phase
  • commit phase

筹备阶段prepare phase

为了实现筹备阶段,除了commit point机器外,其它的数据库机器依照以下步骤执行:

  • 每个节点查看本人是否被其它节点所援用,如果有,就告诉这些节点筹备提交(进入prepare阶段)
  • 每个节点查看本人运行的事务,如果发现本地运行的事务不做批改数据操作,则跳过前面的步骤,间接返回一个read only给全局协调过程。
  • 如果事务须要批改数据,为事务调配相应的资源用于保障批改的失常进行。
  • 对事物做的批改,记录redo信息。
  • 本地redo保障事务失败后的回滚。
  • 当下面的工作都胜利后,给全局协调过程返回准备就绪的信息,反之,返回失败的信号。

提交阶段commit phase

提交阶段按上面的步骤进行:

  • 全局协调器告诉commit point进行提交
  • commit point提交实现。
  • commit point服务器告诉全局协调器提交实现
  • 全局协调器告诉其它节点进行提交
  • 其它节点提交本地的事务,开释资源(提交先后顺序依据Commit Point Strength)
  • 其它节点在redo上记录相应的redo日志,并标注提交实现
  • 其它节点告诉全局协调器提交实现。

分布式事务的完结

分布式事务的完结就是全局协调器和commit point两者之间开释资源的程序。

  • 全局协调器告诉commit point数据库所有节点提交实现。
  • commit point数据库开释和事务相干的所有资源,而后告诉全局协调器。
  • 全局协调器开释本人持有的资源
  • 分布式事务完结

分布式事务的安全性

2PC是否真的能够保障分布式事务的一致性?

  • 实践上是不可能保障分布式事务的一致性。

对于CAP实践能够参见:CAP实践


记得帮我点赞哦!

精心整顿了计算机各个方向的从入门、进阶、实战的视频课程和电子书,依照目录正当分类,总能找到你须要的学习材料,还在等什么?快去关注下载吧!!!

朝思暮想,必有回响,小伙伴们帮我点个赞吧,非常感谢。

我是职场亮哥,YY高级软件工程师、四年工作教训,回绝咸鱼争当龙头的斜杠程序员。

听我说,提高多,程序人生一把梭

如果有幸能帮到你,请帮我点个【赞】,给个关注,如果能顺带评论给个激励,将不胜感激。

职场亮哥文章列表:更多文章

自己所有文章、答复都与版权保护平台有单干,著作权归职场亮哥所有,未经受权,转载必究!