ORACLE事务的四大特性

浏览: 1531

原子性

事务是一个完整的操作。事务的各步操作是不可分的(原子的);要么都执行,要么都不执行。

-- 创建表

create table account_money

(

  id    number(4) not null,

  name  varchar2(4) not null,

  money number(5,2) not null

)

;

-- 增加一个检查约束 

alter table account_money

  add constraint CK_money

  check (money>=0);

 

--向张三这个账号增加数据

insert into ACCOUNT_MONEY (ID, NAME, MONEY)

values (1001, '张三', 500.00);

insert into ACCOUNT_MONEY (ID, NAME, MONEY)

values (1002, '张三', 1.00);


增加后的表如下:

       ID    NAME    MONEY 
1    1001    张三    500.00    
2    1002    张三    1.00   

 

以下为oracle事务处理

BEGIN

  --从张三的1001账户转入张三的1002账户

  UPDATE account_money a SET a.Money=a.Money-600 WHERE a.Id='1001';

  UPDATE account_money a SET a.Money=a.Money+600 WHERE a.Id='1002';

  COMMIT;--提交事务

EXCEPTION --异常处理

  WHEN OTHERS THEN ROLLBACK;--出现异常就回滚

  Dbms_Output.Put_Line('转账异常,转账失败');


在上述代码中,因为账户设置了检查约束,当账户小于0时,就会出现异常,如果不进行事务异常处理,那么第二条更新语句会被执行。当做了事务异常处理后,当出现异常就会回滚。

image

一致性

在事务操作前后,数据必须处于一致状态。是一个业务规则约束的范畴。

同样使用以上的表来做以说明:

DECLARE

  account_a account_money.Money%TYPE;

  account_b account_money.Money%TYPE;

BEGIN

  SELECT a.money INTO account_a FROM account_money a WHERE a.Id='1001'; 

  SELECT a.money INTO account_b FROM account_money a WHERE a.Id='1002'; 

  Dbms_Output.Put_Line('转账前A账户余额:'||account_a);

  Dbms_Output.Put_Line('转账前B账户余额:'||account_b);

  Dbms_Output.Put_Line('转账前总余额:'||(account_a+account_b));

  UPDATE account_money SET money=money-100 WHERE ID='1001';

  UPDATE account_money SET money=money+100 WHERE ID='1002';

  COMMIT;

  SELECT a.money INTO account_a FROM account_money a WHERE a.Id='1001'; 

  SELECT a.money INTO account_b FROM account_money a WHERE a.Id='1002'; 

  Dbms_Output.Put_Line('转账后A账户余额:'||account_a);

  Dbms_Output.Put_Line('转账后B账户余额:'||account_b);

  Dbms_Output.Put_Line('转账后总余额:'||(account_a+account_b));

  EXCEPTION

    WHEN OTHERS THEN

      Dbms_Output.Put_Line('转账失败,业务取消');

  SELECT a.money INTO account_a FROM account_money a WHERE a.Id='1001'; 

  SELECT a.money INTO account_b FROM account_money a WHERE a.Id='1002'; 

  Dbms_Output.Put_Line('停止转账后A账户余额:'||account_a);

  Dbms_Output.Put_Line('停止转账后B账户余额:'||account_b);

  Dbms_Output.Put_Line('停止转账后总余额:'||(account_a+account_b));

END;

image

 

执行上段代码,

执行第一遍:

转账前A账户余额:500
转账前B账户余额:1
转账前总余额:501
转账后A账户余额:400
转账后B账户余额:101
转账后总余额:501

image

执行第二遍:

转账前A账户余额:400
转账前B账户余额:101
转账前总余额:501
转账后A账户余额:300
转账后B账户余额:201
转账后总余额:501

执行第三遍:

转账前A账户余额:300
转账前B账户余额:201
转账前总余额:501
转账后A账户余额:200
转账后B账户余额:301
转账后总余额:501

。。。。。。

当执行第5遍时:A账户的余额为0,如果再执行会出现象呢?

转账前A账户余额:100
转账前B账户余额:401
转账前总余额:501
转账后A账户余额:0
转账后B账户余额:501
转账后总余额:501

执行第6遍,第7遍…………:

转账前A账户余额:0
转账前B账户余额:501
转账前总余额:501
转账失败,业务取消
停止转账后A账户余额:0
停止转账后B账户余额:501
停止转账后总余额:501

 

我们会发现,当我们做事务处理后,总额不会发生变化,当出现异常就不会再执行(或者说回滚)!

 

隔离性

对数据进行修改的所有并发事务是彼此隔离的,这表明事务必须是独立的,它不是以任何方式依赖于或影响其它事务。

每个事务是独立的,我们在PL/SQL中新建两个SQL窗口就以可以做两个事务处理。

我们还是使用以上表,表内容如下:

       ID    NAME    MONEY
1    1001    张三    0.00
2    1002    张三    501.00

第一个SQL窗口:

image

 

第二个SQL窗口:

输入:SELECT * FROM account_money;这条查询语句,我们会发现,第一个SQL窗口没有执行之前的数据。

image

如果我们也在第二个SQL窗口使用update更新数据会怎么样呢?

UPDATE account_money SET money=money+300 WHERE ID='1001';
SELECT * FROM account_money;

他会等待第一个SQL窗口提交事务才会有更新结果!

image

这时我们提交第一个SQL窗口的事务,我们会看到,两个窗口的结果都发生变化。

image

 

我们再提交第二个SQL窗口的事务(在第一个SQL窗口事务没有提交之前是不能提交第二个窗口的事务的),结果也同上图!

 

持久性

事务完成后,它对数据库的修改被永久保存下来。

推荐 0
本文由 华少 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

0 个评论

要回复文章请先登录注册