事务隔离级别¶
隔离属性是 ACID 的四个属性之一,逻辑工作单元必须具备这四个属性才能称为事务。该属性能够使事务免受其它并发事务所执行的更新的影响。每个事务的隔离级别实际上都是可以自定义的。
神通数据库提供以下事务隔离级别:
READ UNCOMMITTED - 读不提交(以读提交来支持该级别)
READ COMMITTED — 读提交
REPEATABLE READ - 可重复读(以可串行化来支持该级别)
SERIALIZABLE — 可串行化
事务的隔离级别决定一个事务在同时存在其它并行运行的事务时,它能够看到什么数据。
READ UNCOMMITTED 表示系统执行脏读或 0 级隔离锁定,也就是既不发出共享锁,也不接受排它锁。当设置该选项时,可以对数据执行未提交读或脏读;在事务结束前可以更改数据内的数值,元组也可以出现在数据集中或从数据集消失。这是四个隔离级别中限制最小的级别。
READ COMMITTED 级别指定在读取数据时控制共享锁以避免脏读,但数据可在事务结束前更改,从而产生不可重复读取或幻像数据。该设置是系统的默认值。
REPEATABLE READ 级别锁定查询中使用的所有数据以防止其他用户更新数据,但是其他用户可以将新的幻像行插入数据集,且幻像行包括在当前事务的后续读取中。因为并发性低于默认隔离级别,所以用户应该只在必要时才使用该选项。
SERIALIZABLE 级别在数据集上放置一个范围锁,以防止其他用户在事务完成之前更新数据集或将行插入数据集内。这是四个隔离级别中限制最大的级别。因为并发级别较低,所以用户应该只在必要时才使用该选项。
注解
神通提供配置参数 ENABLE_DDL_SERIALIZE,默认值为 true,可以在任何隔离级别下仅让 ddl 语句实现 SERIALIZABLE 级别,改为 false 可关闭此功能。
注解
READ COMMITED 保证语句级(state-level)一致性,它保证数据在语句的生命期之内是可见的,但是不能被改变,也就是说一条语句只能看到在它开始之前的数据; SERIALIZABLE 保证事务级一致,它在整个事务生命期中保证数据对所有语句都是可见的,也就是说当前的事务只能看到在这次事务第一条查询或者修改数据的语句执行之前的数据。 在任何一种隔离级别中都可以显式地使用 LOCK TABLE 命令申请封锁。封锁在事务结束时自动释放。当执行影响表定义的命令(如CREATE TABLE)时,这种封锁可从系统自动获得。
另外,设置事务访问模式为只读模式也可以确保事务级一致,任何企图在只读(READ ONLY)事务中修改数据的操作都会产生错误。
注解
READ UNCOMMITTED 和 READ COMMITTED 的事务隔离级别不能保证对某一表中任何读操作在同一个事务中可再现,这是由于其他的并发事务可能插入元组。 因此,既要避免这种情况,又要保证事务能够成功(通过设置可串行化的事务隔离级别,也可以实现该功能,但事务可能会失败), 就必须在事务结束前,使用 LOCK TABLE 命令封锁该表以防止向该表中插入元组。
isql 中设置事务隔离级别的命令语法格式如下:
SET TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE];
例如,把当前事务的隔离级别设置为 SERIALIZABLE 可用下列语句:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
注解
如果当前不在一个事务中,或者系统自动提交属性为关闭状态,或者事务已经被激活,此时进行 SET TRANSACTION 设置事务属性操作将导致出错。
当使用 BEGIN 语句,或者设置自动提交为关闭状态,或者用户执行一个可执行语句时,系统会开始一个事务。 但是以下情况并不会导致事务被激活:1). 语法分析错;2). SET 、RESET 和 SHOW 语句;3). 事务相关的语句(BEGIN、START、COMMIT、END、ROLLBACK、ABORT)。 如果事务因为以上情况而没有被激活,那么之后一旦执行过其他语句激活了事务,此时进行 SET TRANSACTION 设置事务属性操作将导致出错。
示例¶
示例1: 设置事务的隔离级别和读写属性
-- 清理环境
DROP TABLE tab1 CASCADE;
CREATE TABLE tab1 (a INT);
INSERT INTO tab1 VALUES(100);
INSERT INTO tab1 VALUES(200);
SELECT * FROM tab1 ORDER BY a;
A(int) |
------------
100 |
------------
200 |
总数目:2
-- 开启事务
BEGIN;
-- 设置事务的隔离级别 —— SERIALIZABLE
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
-- 设置事务读写属性 —— 只读
SET TRANSACTION READ ONLY;
-- 只读事务中插入数据失败
INSERT INTO tab1 VALUES(300);
ERROR, 事务只读,该语句出错(INSERT INTO tab1 VALUES(300)),请检查配置参数 READ_WRITE_MODE、SESSION_READONLY、ALLOW_UPDATE_UNDER_RUC、TRANSACTION ISOLATION LEVEL
-- 回滚事务
ROLLBACK;
SELECT * FROM tab1 ORDER BY a;
A(int) |
------------
100 |
------------
200 |
总数目:2
-- 删除表
DROP TABLE tab1;
示例2: 事务激活之后设置事务属性失败
-- 清理环境
DROP TABLE tab2 CASCADE;
CREATE TABLE tab2 (a INT);
INSERT INTO tab2 VALUES(100);
INSERT INTO tab2 VALUES(200);
SELECT * FROM tab2 ORDER BY a;
A(int) |
------------
100 |
------------
200 |
总数目:2
-- 开启事务
BEGIN;
SELECT * FROM tab2 ORDER BY a;
A(int) |
------------
100 |
------------
200 |
总数目:2
-- 事务已经被激活,不能再设置事务属性
SET TRANSACTION READ WRITE;
ERROR, 非法的事务状态(transaction already be active)
-- 回滚事务
ROLLBACK;
SELECT * FROM tab2 ORDER BY a;
A(int) |
------------
100 |
------------
200 |
总数目:2
-- 删除表
DROP TABLE tab2;
示例3: 设置冲突的读写属性
-- 开启事务
BEGIN;
-- 设置事务的隔离级别 —— READ UNCOMMITTED
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-- 设置事务读写属性 —— 与隔离级别冲突
SET TRANSACTION READ WRITE;
ERROR, 设置事务属性失败(transaction isolation level is READ UNCOMMITTED, must be read only!)
-- 回滚事务
ROLLBACK;