一致性和并发性

数据一致性是指表示客观世界同一事务状态的数据,不管出现在何时何处都是一致的、正确的和完整的。数据库是一个共享资源,可为多个应用程序所共享,它们同时存取数据库中的数据,这就是数据库的并发操作。此时,如果不对并发操作进行控制,则会存取不正确的数据,或破坏数据库数据的一致性。

DM 利用事务和封锁机制提供数据并发存取和数据完整性。在一事务内由语句获取的全部封锁在事务期间被保持,防止其它并行事务的破坏性干扰。一个事务的 SQL 语句所做的修改在它提交后才可能为其它事务所见。

DM 自动维护数据库的一致性和完整性,并允许选择实施事务级读一致性,它保证同一事务内的可重复读,为此 DM 提供用户各种手动上锁语句和设置事务隔离级别语句。

本章介绍 DM 中和事务管理相关的 SQL 语句和手动上锁语句。在本章各例中,如不特别说明,各例的当前用户均为建表者 SYSDBA。

9.1 DM 事务相关语句

DM 中事务是一个逻辑工作单元,由一系列 SQL 语句组成。DM 把一个事务的所有 SQL 语句作为一个整体,即事务中的操作,要么全部执行,要么一个也不执行。

9.1.1 事务的开始

DM 没有提供显式定义事务开始的语句,第一个可执行的 SQL 语句(除登录语句外)隐含事务的开始。

9.1.2 事务的结束

用户可以使用显式的提交或回滚语句来结束一个事务,也可以隐式地提交一个事务。

1. 提交语句

语法格式

COMMIT [WORK] [IMMEDIATE|BATCH] [WAIT|NOWAIT];

参数

  1. WORK 支持与标准 SQL 的兼容性,COMMIT 和 COMMIT WORK 等价;
  2. IMMEDIATE 目前仅语法支持,无实际作用;
  3. BATCH 目前仅语法支持,无实际作用。指定 BATCH 时必须指定 WAIT 或 NOWAIT,否则报语法错误;
  4. WAIT 事务提交等待事务刷盘;
  5. NOWAIT 事务提交不等待事务刷盘。

功能

该语句使当前事务工作单元中的所有操作“永久化”,并结束该事务。

举例说明

例 1 插入数据到表 DEPARTMENT 并提交。

INSERT INTO RESOURCES.DEPARTMENT(NAME) VALUES('采购部门');
COMMIT WORK;

例 2 插入数据到表 DEPARTMENT 并提交,提交不等待事务刷盘。

INSERT INTO RESOURCES.DEPARTMENT(NAME) VALUES('采购部门');
COMMIT WORK IMMEDIATE NOWAIT;

2.回滚语句

语法格式

ROLLBACK [WORK];

功能

该语句回滚(废除)当前事务工作单元中的所有操作,并结束该事务。

使用说明

建议用户退出时,用 COMMIT 或 ROLLBACK 命令来显式地结束应用程序。如果没有显式地提交事务,而应用程序又非正常终止,则最后一个未提交的工作单元被回滚。特别说明:ALTER TABLESPACE 和 ALTER USER 两种 DDL 语句是不能回滚的。

举例说明

例 插入数据到表 DEPARTMENT 后回滚。

(1)往表DEPARTMENT中插入一个数据
INSERT INTO RESOURCES.DEPARTMENT(NAME) VALUES('销售部门');
(2)查询表DEPARTMENT
SELECT * FROM RESOURCES.DEPARTMENT;
//部门名为'销售部门'的记录可查询到
(3)回滚插入操作
ROLLBACK WORK;
(4)查询表DEPARTMENT
SELECT * FROM RESOURCES.DEPARTMENT;
//*插入操作被回滚,表DEPARTMENT中不存在部门名为'销售部门'的记录

3.隐式提交

当遇到 DDL 语句时,DM 数据库会自动提交前面的事务,然后开始一个新的事务执行 DDL 语句。这种事务提交被称为隐式提交。DM 数据库在遇到以下 SQL 语句时自动提交前面的事务:

  1. CREATE;
  2. ALTER;
  3. TRUNCATE;
  4. DROP;
  5. GRANT;
  6. REVOKE;
  7. 审计设置语句。

9.1.3 保存点相关语句

SAVEPOINT 语句用于在事务中设置保存点。保存点提供了一种灵活的回滚,事务在执行中可以回滚到某个保存点,在该保存点以前的操作有效,而以后的操作被回滚掉。一个事务中可以设置多个保存点。用户可通过 V$TRX_SAVEPOINT 动态视图查询所有活动事务的保存点信息。

1.设置保存点

语法格式

SAVEPOINT <保存点名>;

参数

< 保存点名 > 指明保存点的名字。

使用说明

一个事务中可以设置多个保存点,且一个事务中可创建的最大保存点个数由 INI 参数 SAVEPOINT_LIMIT 决定,可根据需要动态调整;该参数缺省值为 512,即单个事务中默认最大可创建 512 个保存点。重复创建名字相同的保存点,先创建的保存点会失效,回滚时以后创建的保存点为准。

2.回滚到保存点

语法格式

ROLLBACK [WORK] TO SAVEPOINT <保存点名>;

参数

  1. WORK 支持与标准 SQL 的兼容性,ROLLBACK 和 ROLLBACK WORK 等价;
  2. < 保存点名 > 指明部分回滚时要回滚到的保存点的名字。

图例

回滚保存点

回滚保存点

使用说明

回滚到保存点后事务状态和设置保存点时事务的状态一致,在保存点以后对数据库的操作被回滚。

举例说明

例 插入数据到表 ADDRESS_TYPE 后设置保存点,然后再插入另一数据,回滚到保存点。

(1)往表ADDRESS_TYPE中插入一个数据
INSERT INTO PERSON.ADDRESS_TYPE(NAME) VALUES('发货地址');
(2)查询表ADDRESS_TYPE
SELECT * FROM PERSON.ADDRESS_TYPE;
//地址类型名为'发货地址'的记录已经被插入到表中
(3)设置保存点
SAVEPOINT A;
(4)往表ADDRESS_TYPE中插入另一个数据
INSERT INTO PERSON.ADDRESS_TYPE(NAME) VALUES('家庭地址');
(5)回滚到保存点
ROLLBACK TO SAVEPOINT A;
(6)查询表ADDRESS_TYPE
SELECT * FROM PERSON.ADDRESS_TYPE;
//插入操作被回滚,ADDRESS_TYPE中不存在地址类型名为'家庭地址'的记录

3.销毁保存点

语法格式

RELEASE SAVEPOINT <保存点名>;

参数

< 保存点名 > 指明要销毁的保存点的名字。

图例

销毁保存点

销毁保存点.jpg

使用说明

销毁指定的保存点,同时销毁指定保存点之后的保存点。

举例说明

例 设置多个保存点后销毁其中的保存点。

(1)设置保存点A、B、C、D和E
SAVEPOINT A;
SAVEPOINT B;
SAVEPOINT C;
SAVEPOINT D;
SAVEPOINT E;
(2)查询保存点
SELECT * FROM V$TRX_SAVEPOINT;
//可以查询到保存点A、B、C、D和E
(3)销毁保存点C
RELEASE SAVEPOINT C;
(4)查询保存点
SELECT * FROM V$TRX_SAVEPOINT;
//只能查询到保存点A和B,保存点C、D和E被销毁

上述三个保存点相关语句均支持用户自定义变量以及存储过程的参数。

当设置 dm.ini 中参数 MS_PARSE_PERMIT=2 时(该参数为静态参数,修改后需要重启服务器),保存点名支持用户自定义变量以及存储过程的参数,需要在变量前增加 @ 标识符,最终保存点名全部会转换为大写。

例 设置 ini 参数 MS_PARSE_PERMIT=2。

SP_SET_PARA_VALUE (2,'MS_PARSE_PERMIT',2);
DECLARE
NAME VARCHAR(20)='abc';
BEGIN
savepoint @name;      //生成保存点ABC
Release savepoint @name;  //销毁保存点ABC
savepoint @name;      //生成保存点ABC
Rollback to savepoint @name;  //回滚到保存点ABC
END;
/

CREATE OR REPLACE PROCEDURE p1(name VARCHAR(128))
AS
BEGIN
savepoint @name;
SELECT * FROM V$TRX_SAVEPOINT;
END;
/

call p1('abc');

9.1.4 设置事务隔离级及读写特性

事务的隔离级描述了给定事务的行为对其它并发执行事务的暴露程度。通过选择三个隔离级中的一个,用户能增加对其它未提交事务的暴露程度,获得更高的并发度。DM 允许用户改变未启动的事务的隔离级和读写特性,即下列语句必须在事务开始时执行,否则无效。

1.设置事务隔离级语句

事务的隔离级描述了给定事务的行为对其它并发执行事务的暴露程度。通过选择三个隔离级中的一个,用户能增加对其它未提交事务的暴露程度,获得更高的并发度。

语法格式

SET TRANSACTION ISOLATION LEVEL <事务隔离级>;
<事务隔离级> ::= READ COMMITTED | READ UNCOMMITTED | SERIALIZABLE

图例

设置事务隔离级

设置事务隔离级

使用说明

  1. 该语句设置事务的隔离级别:

√ 读提交(READ COMMITTED):DM 默认级别,保证不读脏数据;

√ 读未提交(READ UNCOMMITTED):可能读到脏数据;

√ 可串行化(SERIALIZABLE):事务隔离的最高级别,事务之间完全隔离。

一般情况下,使用读提交隔离级别可以满足大多数应用,如果应用要求可重复读以保证基于查询结果的更新的正确性就必须使用可重复读或可串行读隔离级别。在访问只读表和视图的事务,以及某些执行 SELECT 语句的事务(只要其他事务的未提交数据对这些语句没有负面效果)时,可以使用读未提交隔离级。

  1. 只能在事务未开始执行前设置隔离级,事务执行期间不能更改隔离级。

2.设置事务读写属性的语句

语法格式

SET TRANSACTION <事务读写属性>;
<事务读写属性> ::= READ ONLY | READ WRITE

参数

  1. READ ONLY 只读事务,该事务只能做查询操作,不能更新数据库;
  2. READ WRITE 读写事务,该事务可以查询并更新数据库,是 DM 的默认设置。

图例

设置事务读写属性

设置事务读写属性

语句功能

该语句设置事务的读写属性。

3.设置某条查询语句为脏读

DM 允许用户在 SELECT 语句的末尾加上 WITH UR 以指定当前查询语句的隔离级为读未提交,即允许脏读,并在该语句结束时自动恢复为原来的隔离级。

举例说明

例 会话 1 创建表 T,插入一行数据且不提交,会话 2 查询表 T,因为缺省的事务隔离级为读提交,此时查询不到数据,但是当会话 2 在 SELECT 语句末尾加上 WITH UR 时,可以查询到会话 1 插入的还未提交的数据。

//会话1执行
SQL> CREATE TABLE T(C1 INT, C2 INT);
操作已执行
已用时间: 4.320(毫秒). 执行号:53700.
SQL> INSERT INTO T VALUES(1,1);
影响行数 1
已用时间: 0.573(毫秒). 执行号:53701.

//会话2执行
SQL> SELECT * FROM T;
未选定行
已用时间: 1.691(毫秒). 执行号:53800.
SQL> SELECT * FROM T WITH UR;
 行号    C1     C2
---------- ----------- -----------
1     1      1
已用时间: 0.532(毫秒). 执行号:53801.

9.2 DM 手动上锁语句

DM 的隐式封锁足以保证数据的一致性,但用户可以根据自己的需要手动显式锁定表,允许或禁止在当前用户操作期间其它用户对此表的存取。DM 提供给用户四种表锁的封锁:意向共享锁(IS)、共享锁(S)、意向排他锁(IX)和排他锁(X),并且支持同时执行共享锁(S)和意向排他锁(IX)的封锁,即共享意向排他锁(S+IX)。

语法格式

LOCK TABLE [<模式名>.]<表名> IN <封锁方式> MODE [NOWAIT];
<封锁方式>::=
INTENT SHARE |
ROW SHARE |
SHARE UPDATE |
INTENT EXCLUSIVE |
ROW EXCLUSIVE |
SHARE |
EXCLUSIVE |
SHARE INTENT EXCLUSIVE |
SHARE ROW EXCLUSIVE

图例

DM 手动上锁语句

DM 手动上锁语句

使用说明

  1. 意向共享表封锁:INTENT SHARE TABLE LOCKS (IS)

该封锁表明该事务封锁了表上的一些元组并试图修改它们(但是还未做修改,其它事务可读这些元组,但是不能修改这些元组)。意向共享表封锁是限制最少的锁,提供了表上最大的并发度。

1)等价关键字:INTENT SHARE、ROW SHARE、SHARE UPDATE。

2)允许操作:

其他事务对该表的并发查询、插入、更新、删除或在该表上进行封锁,其他事务可以同时上意向共享锁(IS)、意向排他锁(IX)和共享锁(S)。

3)禁止操作:

其它事务以排他锁方式(X)存取该表。

LOCK TABLE tablename IN EXCLUSIVE MODE;
  1. 意向排他表封锁:INTENT EXCLUSIVE TABLE LOCKS (IX)

该锁表明该事务对表的元组进行一次或多次修改(其它事务不能访问这些元组), 行排他表封锁较行共享表封锁稍严格。

1)等价关键字:INTENT EXCLUSIVE、ROW EXCLUSIVE。

2)允许操作:

其它事务并行查询、插入、更新、删除或封锁该表上行,允许多个事务在同一表上获得意向排他锁(IX)和意向共享锁(IS)。

3)禁止操作:

其它事务对表执行共享锁(S)、排他锁(X)或共享意向排他锁(S+IX)封锁。

LOCK TABLE tablename IN SHARE MODE;
LOCK TABLE tablename IN EXCLUSIVE MODE;
LOCK TABLE tablename IN SHARE INTENT EXCLUSIVE MODE;
  1. 共享表封锁:SHARE TABLE LOCKS (S)

该锁表明该事务访问表中所有元组,其他事务不能对该表做任何更新操作。

1)关键字:SHARE。

2)允许操作:

其它事务在该表上作查询,但是不允许作修改,且允许多个事务在同一表上并发地持有共享表封锁(S)。

3)禁止操作:

其它事务对表执行意向排他锁(IX)、排他锁(X)或共享意向排他锁(S+IX)封锁。

LOCK TABLE tablename IN INTENT EXCLUSIVE MODE;
LOCK TABLE tablename IN EXCLUSIVE MODE;
LOCK TABLE tablename IN SHARE INTENT EXCLUSIVE MODE;
  1. 排他表封锁:EXCLUSIVE TABLE LOCKS (X)

该封锁是表封锁中最严格的方式,只允许持有封锁的事务可对该表进行修改。

1)关键字:EXCLUSIVE。

2)允许操作:

不允许任何操作。

3)禁止操作:

其它事务对表执行任何 DML 语句,即不能插入、修改和删除该表中的行,封锁该表中的行或以任何方式封锁表。

用户上锁成功后锁将一直有效,直到当前事务结束时,该锁被系统自动解除。

  1. 共享意向排他表封锁:SHARE INTENT EXCLUSIVE TABLE LOCKS (S+IX)

该锁是共享锁和意向排他锁的组合,表明该事务访问表中所有元组,允许其他事务在该表上做查询,但不允许对该表做任何更新操作。

1)等价关键字:SHARE INTENT EXCLUSIVE、SHARE ROW EXCLUSIVE。

2)允许操作:

其它事务在该表上执行查询操作,或者在该表上执行意向共享锁(IS)封锁。

3)禁止操作:

其它事务对表执行任何 DML 语句,即不能插入、修改和删除该表中的行,或者对表执行意向排他锁(IX)、共享锁(S)或排他锁(X)封锁。

  1. 当使用 NOWAIT 时,若不能立即上锁成功则立刻返回报错信息,不再等待。

举例说明

例 当用户 SYSDBA 希望独占某表,他可以对该表显式地上排他锁。

LOCK TABLE PERSON.ADDRESS IN EXCLUSIVE MODE;
微信扫码
分享文档
扫一扫
联系客服