ORA-14551: cannot perform a DML operation inside a query
在执行一个有读写的函数调用的sql查询时,报错:
ORA-14551: cannot perform a DML operation inside a query
如图:
经查,
对数据库有写操作(INSERT、UPDATE、DELETE、CREATE、ALTER、COMMIT)的函数,是无法简单的用SQL来调用的.
使用"自主事物",可以解决这个问题.
其实"自主事物"的功能,主要是解决回滚时,标记了PRAGMA AUTONOMOUS_TRANSACTION;的代码块不受外面调用的事物作用.
在解决触发器更新不成功时,如果按默认,记录日志的也将回滚,用该方法强制记录日志,效果较好.
以下为转载:
建立自由性交易, 使用名为autonomous_transaction的编译指示(编译命令,如, #include), 这个编译命令要放在declare里面.
Delcare or replace procedure procedure_name(params, types)
AS
PRAGMA AUTONOMOUS_TRANSACTION;
当程序执行的时候,pl/sql 会把autonomous_transaction当成独立存在的区域来处理.
用途是用在记录程序事件,不影响程序的进行.
一切用pl/sql 代码说话:
/* Formatted on 2006/04/27 14:05 (Formatter Plus v
--test autonomous transaction
CREATE TABLE logging_infos(log_info VARCHAR2(200), log_time DATE);
COMMIT ;
/* Formatted on 2006/04/27 14:05 (Formatter Plus v
--create autonomous transaction procedure
CREATE OR REPLACE PROCEDURE logging_info (
log_info_in VARCHAR2,
log_time_in DATE)
--If your procedure's name is exit in oracle( DB) , then you cann't use it to declare a procedure with the same name
AS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO logging_infos
(log_info, log_time)
VALUES (log_info_in, log_time_in);
COMMIT;
END;
books;
--create main procedure
CREATE OR REPLACE PROCEDURE book_insert (
isbn_in VARCHAR2,
title_in VARCHAR2,
summary_in VARCHAR2,
author_in VARCHAR2,
date_published_in DATE,
page_count_in NUMBER)
AS
BEGIN
INSERT INTO books(isbn, title, author, date_published,page_count)
VALUES (isbn_in, title_in, author_in, date_published_in,age_count_in);
-- call autonomous transcation
logging_info ('aaron_sys', SYSTIMESTAMP);
ROLLBACK;
--rollback for main procedure , not the autonomous transcation
EXCEPTION
WHEN OTHERS
THEN
dbms_ouput.put_line (SQLERRM);
END;
--test the main procedure
BEGIN
book_insert ('ISBN987654321',TEST2','summary:ddddd','Aaron',O_DATE ('
END;
--successfuly completed
SELECT *
FROM books; ---doesn't have the add info
SELECT *
FROM logging_infos; --the logging info is added .
自动交易(autonomous_transaction 繁体版本的书,简体翻译成自由性交易或事前交易,还是觉得自由性交易比较好) , 一定要用commit or rollback, 如果不用的结果就是:
可以编译,但是在执行的时候会提示:ORA-06519: active autonomous transaction detected and rolled back
ORA-06512: at "SYS.LOGGING_INFO", line 10
ORA-06512: at "SYS.BOOK_INSERT", line 15
ORA-06512: at line 2
建立自由性交易, 使用名为autonomous_transaction的编译指示(编译命令,如, #include), 这个编译命令要放在declare里面.
Delcare or replace procedure procedure_name(params, types)
AS
PRAGMA AUTONOMOUS_TRANSACTION;
当程序执行的时候,pl/sql 会把autonomous_transaction当成独立存在的区域来处理.
用途是用在记录程序事件,不影响程序的进行.
---------------------------------------------------------------------------------
在触发器中操作触发此触发器的表,用PRAGMA AUTONOMOUS_TRANSACTION选项。
15.1为何使用自治事务 无法回滚的审计
一般情况下利用触发器禁止某些对表的更新等操作时,若记录日志,则触发器最后抛出异常时会造成日志回滚。利用自治事务可防止此点。
避免变异表
即在触发器中操作触发此触发器的表
在触发器中使用DDL 写数据库
对数据库有写操作(INSERT、UPDATE、DELETE、CREATE、ALTER、COMMIT)的存储过程或函数是无法简单的用SQL来调用的,此时可以将其设为自治事务,从而避免ORA-14552(无法在一个查询或DML中执行DDL、COMMIT、ROLLBACK)、ORA-14551(无法在一个查询中执行DML操作)等错误。需要注意的是函数必须有返回值,但仅有IN参数(不能有OUT或IN/OUT参数)。
开发更模块化的代码
在大型开发中,自治事务可以将代码更加模块化,失败或成功时不会影响调用者的其它操作,代价是调用者失去了对此模块的控制,并且模块内部无法引用调用者未提交的数据。
15.2 如何工作 事务控制
DECLARE整个块都是属于父事务的,自治事务从离PRAGMA后的第一个BEGIN开始,只要此BEGIN块仍在作用域,则都属于自治事务。例如在DECLARE模块中声明一个写数据库的函数,则此函数虽然在自治事务所在存储过程执行,但其属于父事务;而自治事务中调用的任何函数和存储过程、激发的任何触发器等均为此自治事务的一部分。
自治事务可以嵌套,嵌套深度等只受INIT.ORA参数TRANSACTIONS(同时并发的事务数,缺省为SESSIONS的1.1倍)制约。
作用域
1. 包中的变量
自治事务可看到并修改父事务的变量,父事务也会察觉到这一改变,且不存在回滚问题。
2. 会话设置/参数
自治事务与父事务共享同一个会话环境,通过ALTER SESSION作的修改对整个会话均有效。但SET TRANSACTION是事务级的,仅对提起修改的事务有效。
3. 数据库修改
父事务已提交的修改对自治事务可见,未提交的对自治事务不可见,自治事务的修改对父事务是否可见取决于隔离级别(Isolation Level)。
对于游标,取决于其打开的位置,若其在父事务中打开,则之前父事务未提交的修改对其是有效的,在自治事务中这些修改也可见;而在自治事务中打开,则父事务未提交的修改不可见。
若使用缺省的READ COMMITTED隔离级别,则自治事务的修改对父事务可见;若改用SERIALIZABLE,则不可见。
4. 锁
父事务与自治事务是完全不同的事务,因此无法共享锁等。
结束一个自治事务必须提交一个COMMIT、ROLLBACK或执行DDL。
保存点无法在自治事务中回滚到父事务中的一个保存点,只能在内部使用保存点。
15.3 最后说明 不支持分布式事务截至8.1.7在自治事务中不支持分布式事务
仅可用PL/SQL 全部事务回滚若自治事务出错,则全部回滚,即便父事务有异常处理模块。
事务级临时表每个会话仅一个事务可访问事务级临时表(多个会话中的事务可并发操作)。
15.4 可能遇到的错误
ORA-06519 – 检查到活动自治事务,回滚——退出自治事务时没有提交、回滚或DDL操作
ORA-14450 – 试图访问正在使用的事务级临时表
ORA-00060 – 等待资源时检查到死锁