oracle事务特性详解

原子性

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

-- 建立表
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事务处理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时,就会出现异常,若是不进行事务异常处理,那么第二条更新语句会被执行。当作了事务异常处理后,当出现异常就会回滚。3d

image

一致性

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

一样使用以上的表来作以说明:事务

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

 

执行上段代码,ci

执行第一遍:get

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

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窗口事务没有提交以前是不能提交第二个窗口的事务的),结果也同上图!

 

持久性

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

相关文章
相关标签/搜索