1、事务
介绍事务的四大特性(原子性,一致性,隔离性,永久性)和相应的例子来演示
===============================================
银行账号里的转账, 就是一个好的学习事务例子:
假设有2个账号, A账号和B账号 。
A 账号 转给 B 账号 100块钱,
(2个动作在里面, 1是A账号减去100块,2是B账号增加100块钱 ,2个动作不可分割-原子性)
如果当 B账号钱没有增加的时候, 那么A账号的钱不应该减少, 保持一致性。
CREATE TABLE zhang_hao( id integer, zhang_hu varchar(25), jin_e integer);
INSERT INTO zhang_hao VALUES(1,'A',1000);
INSERT INTO zhang_hao VALUES(2,'B',500);
#commit与rollback
在commit之前,可以rollback回滚操作;
commit之后,就回滚不了操作了;
#更新一条数据, 会出现2个用户同时更新的情况
在第一个用户修改完数据后并没有commit,就会造成第二个操作人员查到的还是修改之前的信息,
这就导致了操作误差。
解决并发一个办法:
当我在更新的时候 其他用户不能进行修改, 可以说是加上一个排它锁(隔离性)。
SELECT * FROM zhang_hao FOR UPDATE;
这样sys账号 就不能更新,在一个等待的状态中,当scott用户执行了commit操作后,sys才可以更新数据;
#A给B汇钱100-A减少100
#A给B汇钱100-B增加100
#######
------------------------
下面一个完整的例子说明:
A账号转800块钱给B账号。
这就要注意一个问题, 当A账号的钱转出去了,中途出现错误,B账号没有收到。
这种情况我们就不应该减少A账号的钱, 不执行操作, 做一个回滚。
------------------------
下面代码演示上面所说的情况
先随便创建一张表
create table test( tt varchar(30) );
SQL> create or replace procedure zh_proc
2 as
3 begin
4 savepoint mystart; 创建还原点
5 update zhang_hao set jin_e=200 where zhang_hu='A';
6 insert into test values('dd');
7 update zhang_hao set jin_e=1300 where zhang_hu='B';
8 commit;
9 exception
10 when others then
11 rollback to mystart;
12 end;
13 /
也就是说:
5 update zhang_hao set jin_e=200 where zhang_hu='A';
6 insert into test values('dd');
7 update zhang_hao set jin_e=1300 where zhang_hu='B';
这3条语句任意一条出现执行错误, 都会回滚 rollback 到 开始的地方 mystart 。把3条语句看成一个整体。
删除 test 表
SQL> drop table test;
目的为了 执行 SQL> drop table test; 出现错误
SQL> execute zh_proc;
BEGIN zh_proc; END;
*
ERROR at line 1:
ORA-06550: line 1, column 7:
PLS-00905: object SCOTT.ZH_PROC is invalid
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
SQL> select * from zhang_hao;
ID ZHANG_HU JIN_E
---------- ------------------------- ----------
1 A 1000
2 B 500
可以证明 update zhang_hao set jin_e=200 where zhang_hu='A'; 这条语句被回滚了。
现在我们把test表新建回去
create table test( tt varchar(30) );
SQL> execute zh_proc;
PL/SQL procedure successfully completed.
SQL> select * from zhang_hao;
ID ZHANG_HU JIN_E
---------- ------------------------- ----------
1 A 200
2 B 1300
这样他就会成功提交执行那3条sql语句。
2、触发器
#定义
触发器是一个特殊的存储过程。
区别就是在于, 存储过程需要去调用,而触发器无需调用,在执行某些操作的时候,会自动执行。
一般当表或者视图执行 增,删,改 操作的时候,就会自动执行触发器中的PL SQL 语句块。
还有一个区别, 创建触发器是不带参数的, 而 存储过程 可带可不带 参数。
===========================================
下面一个例子进行演示
数据库行级触发器 - 对每一行(每一条记录进行检查) 动作都触发 FOR EACH ROW
创建一个学生表:
CREATE TABLE xue_sheng( id integer, xing_ming varchar(25),xing_bie number, fen_shu number, b_id integer);
INSERT INTO xue_sheng VALUES(1,'ZhanSan',1,80,1);
INSERT INTO xue_sheng VALUES(2,'LiSi',1,90,2);
INSERT INTO xue_sheng VALUES(3,'ZhanHong',0,75,2);
INSERT INTO xue_sheng VALUES(4,'ChenXiaoMing',1,85,1);
创建一个班级表:
CREATE TABLE ban_ji( id integer , ban_ji varchar(25));
INSERT INTO ban_ji VALUES(1,'1-(1)');
INSERT INTO ban_ji VALUES(2,'1-(2)');
----------------------------------------------------------
#创建一个删除行级触发器 trigger
当删除班级表的一个id , 那么它会自动把学生表所属的班级的学生也会删除
执行删除操作的时候, 建立一个 old内存表, old表和ban_ji表 结构完全一样
所以上面的 old.id 可以理解成 ban_ji班级表的 id
#创建一个插入行级触发器
当插入数据时候,先插入到 new 表,new表和班级表结构也是一样的。 然后在插入到 真正的表,
所以 new.id 和 ban_ji班级表id 对应的。
#更新trigger
级联更新 同时涉及到 old.id 和 new.id
总结一下触发器: 主要是对 old.id 和 new.id 的理解,还有要注意触发器建立所在表的选择。
转载于:https://blog.51cto.com/jasonliping/1404715