您的位置:首页 > 数据库

PL / SQL 101:定义和管理事务

2018-12-21 17:05 429 查看

如果您有一个只读数据库,则不必担心事务。但是对于你将要构建的几乎所有应用程序,情况并非如此。因此,交易的概念和管理对于您的应用程序的成功至关重要。

事务是Oracle数据库作为一个单元处理的一个或多个SQL语句的序列:要么执行所有语句,要么都不执行。事务隐含地从获取TX锁的任何操作开始:

  • 发出修改数据的语句(例如,插入,更新,删除,合并)

  • 发出SELECT ... FOR UPDATE语句时

  • 使用SET TRANSACTION语句或DBMS_TRANSACTION包显式启动事务时

发出COMMIT或ROLLBACK语句会明确结束当前事务。

本文将介绍如何使用以下语句和功能定义,管理和控制应用程序中的事务:

  • 提交和回滚

  • 保存点

  • 自治交易

  • SET TRANSACTION语句

您可以在下面的事务处理和控制(doc)以及Oracle Live SQL和Oracle Dev Gym资源的链接中找到更多详细信息。

提交和回滚

回想一下事务的定义:“事务是Oracle数据库作为一个单元处理的一个或多个SQL语句的序列:要么执行所有语句,要么都不执行。” 当所有语句都“执行”时,这意味着您已将它们提交或保存到数据库中。

使用COMMIT语句保存所有更改,并使其对其他用户可见。请记住:在提交之前,没有人能够看到特定会话中所做的更改。提交后,每个有权访问受影响表的用户现在都可以看到表的新“状态”。

使用ROLLBACK语句撤消自上次提交以来(或自您在会话中启动第一个事务以来)的所有更改。

LiveSQL教程(Oracle Dev Gym上的开发人员数据库课程的一部分)演示了事务管理的这些基本元素。

可是等等!如果您只想撤消会话中的某些更改,但保留其他更改,准备在将来的某个时间点提交,该怎么办?欢迎来到保存点世界。

保存点

保存点允许您回滚部分事务而不是整个事务。每个会话的活动保存点数量不受限制。

回滚到保存点时,标记在该保存点之后的任何保存点都将被删除。回滚的保存点不会被删除。简单的回滚或提交会擦除所有保存点。

保存点名称是未声明的标识符。在事务中重用保存点名称会将保存点从其旧位置移动到事务中的当前点,这意味着回滚到保存点仅影响事务的当前部分。

对于我们之间的递归程序员:如果在递归子程序中标记保存点,则SAVEPOINT语句的新实例在递归下降的每个级别运行,但是您只能回滚到最近标记的保存点。

以下是使用保存点的示例(从同一个LiveSQL教程中提取):

CREATE TABLE toys ( toy_id INTEGER, toy_name VARCHAR2 (100), colour VARCHAR2 (10) ) / DECLARE l_count INTEGER; BEGIN INSERT INTO toys (toy_id, toy_name, colour) VALUES (8, 'Pink Rabbit', 'pink'); SAVEPOINT after_six; INSERT INTO toys (toy_id, toy_name, colour) VALUES (9, 'Purple Ninja', 'purple'); SELECT&nbs
4459
p;COUNT (*) INTO l_count FROM toys WHERE toy_id IN (8, 9); DBMS_OUTPUT.put_line (l_count); ROLLBACK TO SAVEPOINT after_six; SELECT COUNT (*) INTO l_count FROM toys WHERE toy_id IN (8, 9); DBMS_OUTPUT.put_line (l_count); ROLLBACK; SELECT COUNT (*) INTO l_count FROM toys WHERE toy_id IN (8, 9); DBMS_OUTPUT.put_line (l_count); END; / 2 10

自治交易

默认情况下,执行COMMIT语句时,会保存会话中所有未保存的更改。当您回滚时,所有未保存的更改都将被删除。

但有时候,我们只想保存其中一个更改,而不保存其他更改。此方案的最典型用例是错误日志记录。我想将信息写入我的错误日志表并保存,但后来我需要回滚事务(毕竟,有一个错误)。

我可以使用保存点来执行此操作(请参阅上一节),但是当您调用可重用的日志记录程序时,很难一致且可靠。幸运的是,我可以简单地使我的错误记录过程成为一个自治事务。然后,我可以插入错误信息并提交该插入,而不会影响业务事务,随后将回滚该业务事务。

它很容易做到!

只需将此语句添加到过程或函数的声明部分......

PRAGMA AUTONOMOUS_TRANSACTION;

然后适用以下规则:

在关闭子程序并将控制权传递回调用块之前,必须提交或回滚在该子程序中进行的任何DML更改。

如果有任何未保存的更改,PL / SQL引擎将引发ORA-06519异常,如下所示:

CREATE OR REPLACE FUNCTION nothing RETURN INTEGER IS PRAGMA AUTONOMOUS_TRANSACTION; BEGIN UPDATE employees SET last_name = 'abc'; RETURN 1; END; / BEGIN DBMS_OUTPUT.put_line (nothing); END; / ORA-06519: active autonomous transaction detected and rolled back ORA-06512: at "STEVEN.NOTHING", line 10 ORA-06512: at line 2

以下是在错误记录过程中使用此功能的示例:

CREATE OR REPLACE PACKAGE BODY error_mgr IS PROCEDURE log_error (app_info_in IN VARCHAR2) IS PRAGMA AUTONOMOUS_TRANSACTION; c_code CONSTANT INTEGER := SQLCODE; BEGIN INSERT INTO error_log (created_on, created_by, errorcode, callstack, errorstack, backtrace, error_info) VALUES (SYSTIMESTAMP, USER, c_code, DBMS_UTILITY.format_call_stack, DBMS_UTILITY.format_error_stack, DBMS_UTILITY.format_error_backtrace, app_info_in); COMMIT; END; END;

LiveSQL脚本包含完整(和非常基本)的错误记录包。

LiveSQL脚本演示了自治事务编译指示的效果。

SET TRANSACTION语句

使用SET TRANSACTION语句将当前事务建立为只读或读/写,建立其隔离级别,将其分配给指定的回滚段,或为事务指定名称。

当您将事务设置为只读时,查询将返回事务开始时存在的数据,并且 您只能运行select语句。以下是使用此选项的示例,该选项来自Chris Saxon出色的LiveSQL模块:

set transaction read only; select * from toys; update toys set price = price + 1; declare pragma autonomous_transaction; begin update toys set price = 99.00; commit; end; / select * from toys; commit; select * from toys;

以下是在LiveSQL中运行时的结果:

Oracle仅支持两个隔离级别:Read Committed和Serializable。

阅读已提交

这是Oracle数据库的默认模式。使用read committed,您具有语句级一致性。这意味着每个DML命令(选择,插入,更新或删除)都可以在开始之前查看保存的所有数据。其他会话启动后保存的任何更改都将被隐藏。

它使用多版本并发控制(MVCC)来实现。更新或删除行时,会将行的当前状态存储在undo中。因此,其他事务可以使用此撤消来查看过去存在的数据。

序列化

将事务设置为可序列化时,数据库就像您是数据库的唯一用户一样。其他交易所做的更改对您隐藏。Serializable还会阻止您更改由此错误导致的其他事务修改的行:


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  PL / SQL 101