异常
PL/SQL异常是指通过编译的PL/SQL程序在运行时产生的错误。导致异常的原因较多,如内存用尽、硬件故障、违反表的完整性约束、设计缺陷等。PL/SQL提供了异常错误处理机制,可以帮助实现对错误的捕获和处理。当异常发生时,PL/SQL会自动地捕获异常并将程序控制流程转移到异常处理部分的程序。
格式:
exception
when 异常错误名称1 [or 异常错误名称2] then
语句段1;
when 异常错误名称3 [or 异常错误名称4] then
语句段2;
......
when others then
语句段3;
预定义异常
针对一些常见的异常,PL/SQL预定义了一些异常错误
当PL/SQL程序违反了Oracle的规定或超出了系统规定的限制时,就会隐含的引发一个预定义的错误。
自定义异常
有预定义异常自然也有自定义异常,oracle不可能那么细。。。把所有异常都考虑到,所以,我们有时候需要自定义一些异常。
在实际的PL/SQL程序开发过程中,为了具体的业务规则、编程和调试的需要,程序员可以自定义一些异常。
自定义异常必须要声明,并且必须使用raise语句显式的引发。
在更新表中的数据时,如果没有符合条件的记录,则不会更新数据。因为这不是错误,并没有影响表的实际内容,所以不会有错误提示,但可以使用自定义异常的方法来提示。
示例:
(删除一个员工的信息,如果员工不存在,捕捉异常)
declare
dept_no_emp exception;
begin
delete from emp where empno=&eno;
if sql%notfound then
raise dept_no_emp;
else
dbms_output.put_line('删除成功');
end if;
exception
when dept_no_emp then
dbms_output.put_line('该员工不存在');
end;
事务
Oracle的事务不同于sqlserver,sqlserver是只要sql语句正确就提交,不正确就回滚,而Oracle是需要手动提交的,当然你可以设置自动提交打开。。。
事务的ACID特性:
- 原子性(Atomicity)
- 一致性(Consistency)
- 隔离性(Isolation)
- 持久性(durability)
1、原子性(Atomicity)
事务的原子性是指事务中包含的所有操作要么全做,要么不做,也就是说所有的活动在数据库中要么全部反映,要么全部不反映,以保证数据库的一致性。
2、一致性(Consistency)
事务的一致性是指数据库在事务操作前和事务处理后,其中数据必须满足业务的规则约束。
3、隔离性(Isolation)
隔离性是指数据库允许多个并发的事务同时对其中的数据进行读写或修改的能力,隔离性可以防止多个事务的并发执行时,由于它们的操作命令交叉执行而导致数据的不一致性。
4、持久性(durability)
事务的持久性是指在事务处理结束后,它对数据的修改应该是永久的。即便是系统在遇到故障的情况下也不会丢失,这是数据的重要性决定的。
事务和锁
当多个用户同时访问Oracle数据库,执行事务操作(DML语句)时,同时可能有多个用户访问同一个数据库资源,Oracle会自动在被作用的表上加锁,防止其他用户的事务改表的数据,这里对我们用户来说是非常重要的,它会避免使用的数据产生逻辑错误。
如果没有锁定且多个用户同时访问一个数据库,则当他们的事务同时使用相同的数据时可能会发生问题。由于并发操作带来的数据不一致性包括:丢失数据修改、读”脏”数据 (脏读)、不可重复读、产生幽灵数据。
并发访问引发的问题###:
(1)丢失数据修改
当两个不同的事务选择同一行,然后基于最初选定的值更新该行时,会发生丢失更新问题。每个事务都不知道其它事务的存在。最后的更新将重写由其它事务所做的更新,这将导致数据丢失。例如,两个编辑人员制作了同一文档的电子复本。每个编辑人员独立地更改其复本,然后保存更改后的复本,这样就覆盖了原始文档。最后保存其更改复本的编辑人员覆盖了第一个编辑人员所做的更改。如果在第一个编辑人员完成之后第二个编辑人员才能进行更改,则可以避免该问题。
(2)读“脏”数据(脏读)
读“脏”数据是指事务Tl修改某一数据,并将其写回磁盘,事务T2读取同一数据后,Tl由于某种原因被撤消,而此时Tl把己修改过的数据又恢复原值,T2读到的数据与数据库的数据不一致,则T2读到的数据就为“脏”数据,即不正确的数据。例如:一个编辑人员正在更改电子文档。在更改过程中,另一个编辑人员复制了该文档(该复本包含到目前为止所做的全部更改)并将其分发给预期的用户。此后,第一个编辑人员认为目前所做的更改是错误的,于是删除了所做的编辑并保存了文档。分发给用户的文档包含不再存在的编辑内容,并且这些编辑内容应认为从未存在过。如果在第一个编辑人员确定最终更改前任何人都不能读取更改的文档,则可以避免该问题。
(3)不可重复读
事务Tl读取数据后,事务T2执行更新操作,使Tl无法读取前一次结果。不可重复读包括三种情况:事务Tl读取某一数据后,T2对其做了修改,当Tl再次读该数据后,得到与前一不同的值。
(4)产生幽灵数据
按一定条件从数据库中读取了某些记录后,T2删除了其中部分记录,当Tl再次按相同条件读取数据时,发现某些记录消失。Tl按一定条件从数据库中读取某些数据记录后,T2插入了一些记录,当Tl再次按相同条件读取数据时,发现多了一些记录。
加锁是实现数据库并发控制的一个非常重要的技术
数据库是一个多用户使用的共享资源。当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性。加锁是实现数据库并发控制的一个非常重要的技术。当事务在对某个数据对象进行操作前,先向系统发出请求,对其加锁。加锁后事务就对该数据对象有了一定的控制,在该事务释放锁之前”其‘他的事务不能对此数据对象进行更新操作。
两种基本锁类型:
1.排它锁(Exclusive locks,即X锁)
当数据对象被加上排它锁之后,其他的事物不能对它进行读取和修改
2.共享锁(Share locks,即S锁)
加了共享锁的数据可以被其他事务读取,但不能修改数据(还有可能造成幻读)
Oracle数据库的锁类型
根据保护的对象不同,Oracle数据库锁可以分为以下几大类:DML锁(data locks,数据锁),用于保护数据的完整性;DDL锁(dictionary locks,字典锁),用于保护数据库对象的结构,如表、索引等的结构定义;内部锁和闩(internal locks and latches),保护数据库的内部结构。
DML锁的目的在于保证并发情况下的数据完整性,本文主要讨论DML锁。在Oracle数据库中,DML锁主要包括TM锁和TX锁,其中TM锁称为表级锁,TX锁称为事务锁或行级锁。 当Oracle执行DML语句时,系统自动在所要操作的表上申请TM类型的锁。当TM锁获得后,系统再自动申请TX类型的锁,并将实际锁定的数据行的锁标志位进行置位。这样在事务加锁前检查TX锁相容性时就不用再逐行检查锁标志,而只需检查TM锁模式的相容性即可,大大提高了系统的效率。TM锁包括了SS、SX、S、X等多种模式,在数据库中用0-6来表示。不同的SQL操作产生不同类型的TM锁。
在数据行上只有X锁(排他锁)。在Oracle数据库中,当一个事务首次发起一个DML语句时就获得一个TX锁,该锁保持到事务被提交或回滚。当两个或多个会话在表的同一条记录上执行DML语句时,第一个会话在该条记录上加锁,其他的会话处于等待状态。当第一个会话提交后,TX锁被释放,其他会话才可以加锁。
当Oracle数据库发生TX锁等待时,如果不及时处理常常会引起Oracle数据库挂起,或导致死锁的发生,产生ORA-60的错误。这些现象都会对实际应用产生极大的危害,如长时间未响应,大量事务失败等。
事务控制语句
set autocommit on || off || immediate || n;
设置事务的自动提交方式。
immediate和on选项的功能相同。
n表示当oracle数据库执行了n条insert,update,delete或PL/SQL程序块时自动提交。
PS:提交过就无法回滚了,朋友们!!
Tips: delete语句在我们开发过程当中其实并不常用,大部分都是采用了标记删除的手法。假如,你之前在淘宝买了一件商品,后来这件商品没有库存而下架了,你在订单当中就无法查看你之前买的商品了吗?一般情况下,我们并不会真正的把一行数据从数据库之中删除,而是采用了例如:
在数据库中加入一列‘isDelete’属性,1代表被删除了,2代表没有被删除。(最常用的手法)。
1.commit语句
用于提交事务
2.rollback语句
可以将事务回滚到事务的起点或者某个保存点
3.savepoint语句
设置保存点(回滚点)
4.rollback to [回滚点名] 语句
savepoint a;
Insert into dept(deptno,dname,loc) values(80,’市场部’,’hongkong’);
Rollback to a;
Insert into dept(deptno,dname,loc) values(90,’销售部’,’hongkong’);
Commit;
End;
查看事务
匿名事务
查看事务信息使用视图V$TRANSACTION,这个视图必须使用sys或system访问,因为当前事务是匿名事务,所以name字段值为空,
命名事务
begin
Set transaction name ‘insdept’
Insert into dept(deptno,dname,loc) values(21,’sales’,’hongkong’);
End;