欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

oracle事务一致性:原子性

程序员文章站 2022-06-02 11:47:29
...

原子性

事务的动作要么一起成功,要么都不成功,这是事务的原子性。

原子性包括:

  1. 语句级原子性
  2. 过程级原子性
  3. 事务级原子性
  4. DDL与原子性

语句级原子性

如果某条语句(如insert、update)执行成功与否会自动控制事务。

如设置插入前的触发器。

create table t2(cnt int);

insert into t2 values(0);

commit;

create table t(x int check(x>0));

create trigger t_tragger
before insert or update on t for each row
begin
  if(inserting) then
                update t2 set cnt=cnt+1;
  else
    update t2 set cnt=cnt-1;
  end if;
  dbms_output.put_line('I fired and updateed '|| sql%rowcount||'rows');
  
  end;

由于 表t设置了值约束,当插入负数的时候,是不能插入的

insert into t values(1);

此时 表t2中的cnt=1

如果

insert into t values(-1);

会报ora-02290违反检查约束条件
oracle事务一致性:原子性
此时去检查表t2的cnt值没有更新成2,仍然是1.

书《oracle编程艺术》中sqlserver需要显式执行触发器的回滚才能实现触发器的不执行,但是我测试的是可以的。

create table t1 (cnt int)

create table t (v int check(v>0))

create trigger t_tragger
on t
for insert
as 
begin
update t1 set cnt=cnt+1;
end


insert into t1 values(0)

select * from t1

insert into t values(-1)

过程级原子性

测试在存储过程中往表t中插入负数,会不会触发触发器的更新操作

create or replace procedure p
as 
begin
  insert into t values(1);
  insert into t values(-1);
  
  end;
  

当执行

begin
  p;
  end;

会报ora02290错误
oracle事务一致性:原子性
表t 、t2不会插入和更新任何值

如果加入异常判断

  
begin
  p;
  exception
    when others then
      dbms_output.put_line('error'|| sqlerrm);
     -- raise_application_error(-20001,sqlerrm);
  end;

在when others then中
没有对错误抛出处理,只是进行了打印,
那么再执行时不会报错。
此时查询表t/t2会发现值被更新了一次。
这是因为存储过程中的每个Insert语句进行了事务提交,第二句sql因为不满足约束信息,跳转到when others then却没有执行异常处理,就回滚了。但是第一句sql没有回滚,被提交了。

begin
  p;
  exception
    when others then
      --dbms_output.put_line('error'|| sqlerrm);
     raise_application_error(-20001,sqlerrm);
  end;

oracle事务一致性:原子性
这个时候保证了存储中必须全部执行完成后,才能提交事务。
所以在when others then 中必须加上raise 或者raise_application_error的处理,要不然语句的原子性会导致结果的提交,不能保证整个过程的原子性!

事务级原子性

一组SQL语句作为一个工作单元一同执行。数据库从一种一致状态转变为另一种一致状态。

DDL原子性

在oralce中执行DDL操作会导致事务的自动提交
尤其注意的是truncate table会导致事务提交。

但在sqlserver中可以在事务中创建临时表,不会导致事务提交。