1、事务概述
数据库事务是指作为单个逻辑工作单元的一系列操作的集合。一个典型的事务由应用程序中的一组操作序列组成,对于 DM 数据库来说,第一次执行 SQL 语句时,隐式地启动一个事务,以 COMMIT 或 ROLLBACK 语句/方法显式地结束事务。另外,在执行 DDL 前,DM数据库会自动把前面的操作进行提交,DDL 前面的操作作为一个完整的事务结束,DDL语句本身所属事务则根据“DDL_AUTO_COMMIT”配置参数决定是否隐式地提交(注意,无论 DDL_AUTO_COMMIT 参数如何设置,ALTER TABLESPACE 和 ALTER USER 操作总是自动提交的)。 COMMIT 操作会将该语句所对应事务对数据库的所有更新持久化(即写入磁盘),数据库此时进入一个新的一致性状态,同时该事务成功地结束。ROLLBACK 操作将该语句所对应事务对数据库的所有更新全部撤销,把数据库恢复到该事务初启动前的一致性状态。
2、事务四性
2.1原子性
事务的原子性保证事务包含的一组更新操作是原子不可分的,也就是说这些更新操作是一个整体,对数据库而言全做或者全不做,不能部分地完成。这一性质即使在系统崩溃之后仍能得到保证,在系统崩溃之后将进行数据库恢复,用来恢复和撤销系统崩溃时处于活动状态的事务对数据库的影响,从而保证事务的原子性。系统对磁盘上的任何实际数据的修改之前都会将修改操作本身的信息记录到磁盘上。当发生崩溃时,系统能根据这些操作记录当时该事务处于何种状态,以此确定是撤销该事务所做出的所有修改操作,还是将修改的操作重新执行。
2.2一致性
数据一致性是指表示客观世界同一事务状态的数据,不管出现在何时何处都是一致的、正确的、完整的。换句话说,数据一致性是任何点上保证数据以及内部数据结构的完整性,如 B 树索引的正确性。一致性要求事务执行完成后,将数据库从一个一致状态转变到另一个一致状态。它是一种以一致性规则为基础的逻辑属性,例如在转账的操作中,各账户金额必须平衡,这一条规则对于程序员而言是一个强制的规定。事务的一致性属性要求事务在并发执行的情况下事务的一致性仍然满足。
2.3隔离性
事务是隔离的,意味着每个事务的执行效果与系统中只有该事务的执行效果一样,也就是说,某个并发事务所做的修改必须与任何其他的并发事务所做的修改相互隔离。这样,只有当某个值被一个事务修改完并提交后才会影响到另一个事务。事务只会识别另一并发事务修改之前或者修改完成之后的数据,不会识别处于这中间状态的数据。事务的隔离行为依赖于指定的隔离级别。
2.4永久性
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响。即一旦一个事务提交,DBMS 保证它对数据库中数据的改变应该是永久性的。如果 DM 数据库或者操作系统出现故障,那么在 DM 数据库重启的时候,数据库会自动恢复。如果某个数据驱动器出现故障,并且数据丢失或者被损坏,可以通过备份和联机重做日志来恢复数据库。需要注意的是,如果备份驱动器也出现故障,且系统没有准备其他的可靠性解决措施,备份就会丢失,那么就无法恢复数据库了。
3、事务提交
在 DM 数据库中还存在有 3 种事务模式:自动提交模式、手动提交模式和隐式提交模式。
3.1自动提交
除了命令行交互式工具 DISQL 外,DM 数据库缺省都采用自动提交模式。用户通过DM数据库的其他管理工具、编程接口访问 DM 数据库时,如果不手动/编程设置提交模式,所有的 SQL 语句都会在执行结束后提交,或者在执行失败时回滚,此时每个事务都只有一条SQL 语句。
在 DISQL 中,用户也可以通过执行如下语句来设置当前会话为自动提交模式:
SET AUTOCOMMIT ON;
会话1:
SQL> select * from t1;
行号 ID
---------- -----------
1 1
2 2
3 3
4 4
已用时间: 0.320(毫秒). 执行号:1701.
SQL> insert into t1 values(5);
影响行数 1
已用时间: 0.722(毫秒). 执行号:1702.
SQL> select * from t1;
行号 ID
---------- -----------
1 1
2 2
3 3
4 4
5 5
已用时间: 0.179(毫秒). 执行号:1703.
会话2:
[dmdba@lei2 ~]$ disql lei/leileilei
服务器[LOCALHOST:5236]:处于普通打开状态
登录使用时间 : 5.437(ms)
disql V8
SQL> select * from t1;
行号 ID
---------- -----------
1 1
2 2
3 3
4 4
已用时间: 0.538(毫秒). 执行号:1901.
会话1未设置自动提交,会话2查询不到会话1更新的数据。
SQL> set autocommit on;
SQL> insert into t1 values(6);
影响行数 1
已用时间: 0.916(毫秒). 执行号:1704.
会话1设置自动提交,插入数据。
SQL> select * from t1;
行号 ID
---------- -----------
1 1
2 2
3 3
4 4
5 5
6 6
6 rows got
已用时间: 0.293(毫秒). 执行号:1902.
会话2可查询到会话1新插入的数据,即使会话1为执行commit。
3.2手动提交
在手动提交模式下,DM 数据库用户或者应用开发人员明确定义事务的开始和结束,这些事务也被称为显式事务。在 DISQL 中,没有设置自动提交时,就是处于手动提交模式, 此时 DISQL 连接到服务器后第一条 SQL 语句或者事务结束后的第一条语句就标记着事务的开始,可以执行COMMIT或者 ROLLBACK 来提交或者回滚事务。
3.3隐式提交
在手动提交模式下,当遇到 DDL 语句时,DM 数据库会自动提交前面的事务,然后开始一个新的事务执行 DDL 语句。这种事务提交被称为隐式提交。DM 数据库在遇到以下 SQL语句时自动提交前面的事务:CREATE、ALTER、TRUNCATE、DROP、GRANT、REVOKE、审计设置语句。
4、事务回滚
回滚事务是撤消该事务所做的任何更改。回滚有两种形式:DM数据库自动回滚,或者通过程序/ROLLBACK命令手动回滚。除此之外,DM还支持回滚到保存点和语句级回滚。在事务回滚过程中如果访问到损坏的数据页,则会将当前事务信息登记到系统表SYSCRASHTRXS中,SYSCRASHTRXS中的事务会被当做活动事务,保证其他事务不会访问到故障事务修改后的记录。
4.1自动回滚
若事务运行期间出现连接断开,DM数据库都会自动回滚该连接所产生的事务。回滚会撤消事务执行的所有数据库更改,并释放此事务使用的所有数据库资源。DM数据库在恢复时也会使用自动回滚。例如在运行事务时服务器突然断电,接着系统重新启动,DM数据库就会在重启时执行自动恢复。自动恢复要从事务重做日志中读取信息以重新执行没有写入磁盘的已提交事务,或者回滚断电时还没有来得及提交的事务。
4.2手动回滚
在实际应用中,当某条 SQL 语句执行失败时,用户会主动使用 ROLLBACK 语句或者编程接口提供的回滚函数来回滚整个事务,避免不合逻辑的事务污染数据库,导致数据不一致。如果发生错误后确实只用回滚事务中的一部分,则需要用到回滚到SAVE POINT的功能。
4.3回滚到SAVEPOINT
除了回滚整个事务之外,DM 数据库的用户还可以部分回滚未提交事务,即从事务的最末端回滚到事务中任意一个被称为保存点的标记处。用户在事务内可以声明多个被称为保存点的标记,将一个大事务划分为几个较小的片断。之后用户在对事务进行回滚操作时,就可以选择从当前执行位置回滚到事务内的任意一个保存点。例如用户可以在一系列复杂的更新操作之间插入保存点,如果执行过程中一个语句出现错误,用户可以回滚到错误之前的某个保存点,而不必重新提交所有的语句。当事务被回滚到某个保存点后,DM数据库将释放被回滚语句中使用的锁。其他等待“被锁资源”的事务就可以继续执行,需要更新“被锁数据行”的事务也可以继续执行。将事务回滚到某个保存点的过程如下:
1.只回滚保存点之后的语句;
2.保留该保存点,其后创建的保存点都被清除;
3.释放此保存点之后获得的所有锁,保留该保存点之前的锁。
被部分回滚的事务依然处于活动状态,可以继续执行。DM 数据库用户可以使用 SAVEPOINT SAVEPOINT_NAME 命令创建保存点,使用 ROLLBACK TO SAVEPOINT SAVEPOINT_NAME 命令来回滚到保存点SAVEPOINT_NAME。
SQL> select * from t1;
行号 ID
---------- -----------
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
9 rows got
已用时间: 0.295(毫秒). 执行号:2101.
SQL> savepoint t1_9;
操作已执行
已用时间: 0.342(毫秒). 执行号:2102.
SQL> insert into t1 values(10);
影响行数 1
已用时间: 0.715(毫秒). 执行号:2103.
SQL> select * from t1;
行号 ID
---------- -----------
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 10
10 rows got
已用时间: 0.279(毫秒). 执行号:2104.
SQL> rollback to savepoint t1_9;
操作已执行
已用时间: 0.432(毫秒). 执行号:2105.
SQL> select * from t1;
行号 ID
---------- -----------
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
9 rows got
已用时间: 0.278(毫秒). 执行号:2106.
SQL> commit;
操作已执行
已用时间: 0.661(毫秒). 执行号:2107.
SQL> select * from t1;
行号 ID
---------- -----------
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
9 rows got
已用时间: 0.281(毫秒). 执行号:2108.
4.4语句回滚
如果在一个 SQL语句执行过程中发生了错误,此语句对数据库产生的影响将被回滚,回滚后就如同此语句从未执行过,这种操作被称为语句级回滚。语句级回滚只会使此语句所做的数据修改无效,不会影响此语句之前所做的数据修改。当 INI 参数 ROLL_ON_ERR 为缺省值 0 时,在 SQL 语句执行过程中发生的错误,将会导致语句级回滚,例如违反唯一性、死锁(访问相同数据而产生的竞争)、运算溢出等。在SQL 语句解析的过程中发生错误(例如语法错误),由于未对数据产生任何影响,因此不会产生语句级回滚。
5、事务锁定
DM 数据库支持多用户并发访问、修改数据,有可能出现多个事务同时访问、修改相同数据的情况。若对并发操作不加控制,就可能会访问到不正确的数据,破坏数据的一致性和正确性。
封锁机制是实现数据库并发控制的一个非常重要的技术。当事务在对某个数据库对象进行操作前,需要先对其封锁。封锁后事务就对该数据库对象有了一定的控制,在该事务释放锁之前,其他的事务不能对此数据库对象进行相应操作。
5.1锁模式
5.1.1共享锁(S锁)
共享锁(Share Lock,简称 S 锁)用于读操作,防止其他事务修改正在访问的对象。这种封锁模式允许多个事务同时并发读取相同的资源,但是不允许任何事务修改这个资源。
5.1.2排他锁(X锁)
排他锁(Exclusive Lock,简称 X 锁)用于写操作,以独占的方式访问对象,不允许任何其他事务访问被封锁对象;防止多个事务同时修改相同的数据,避免引发数据错误;防止访问一个正在被修改的对象,避免引发数据不一致。一般在修改对象定义时使用。
5.1.3意向锁(I锁)
意向锁(Intent Lock)用于读取或修改被访问对象数据时使用,多个事务可以同时对相同对象上意向锁,DM支持两种意向锁:
5.1.3.1意向共享锁(Intent Share Lock,简称IS锁)
一般在只读访问对象时使用;
5.1.3.2意向排他锁(Intent Exclusive Lock,简称IX锁)
一般在修改对象数据时使用。
5.2锁粒度
5.2.1TID锁
TID锁以事务号为封锁对象,为每个活动事务生成一把TID锁,代替了其他数据库行锁的功能,防止多个事务同时修改同一行记录。DM实现的是行级多版本,每一行记录隐含一个TID字段,用于事务可见性判断。
执行 INSERT、DELETE、UPDATE 操作时,设置事务号到 TID 字段。这相当于隐式地对记录上了一把 TID 锁,INSERT、DELETE、UPDATE 操作不再需要额外的行锁,避免了大量行锁对系统资源的消耗。只有多个事务同时修改同一行记录时,才会产生新的TID锁。同时多版本写不阻塞读的特性,SELECT 操作已经消除了行锁,因此 DM 中不再有行锁的概念。
5.2.2对象锁
对象锁是 DM 新引入的一种锁,通过统一的对象 ID 进行封锁,将对数据字典的封锁和表锁合并为对象锁,以达到减少封锁冲突、提升系统并发性能的目的。
1.数据字典锁
用来保护数据字典对象的并发访问,解决DDL并发和 DDL/DML 并发问题,防止多个事务同时修改同一个对象的字典定义,确保对同一个对象的DDL操作是串行执行的。并防止一个事务在修改字典定义的同时,另外一个事务修改对应表的数据。
2.表锁
表锁用来保护表数据的完整性,防止多个事务同时采用批量方式插入、更新一张表,防止向正在使用 FAST LOADER 工具装载数据的表中插入数据等,保证这些优化后数据操作的正确性。此外,表锁还有一个作用,避免对存在未提交修改的表执行 ALTER TABLE、TRUNCATE TABLE 操作。
为了实现与数据字典锁和表锁相同的封锁效果,从逻辑上将对象锁的封锁动作分为四类:
1)独占访问(EXCLUSIVE ACCESS)
不允许其他事务修改对象,不允许其他事务访问对象,使用X方式封锁
2)独占修改(EXCLUSIVE MODIFY)
不允许其他事务修改对象,允许其他事务共享访问对象,使用S + IX方式封锁
3)共享修改(SHARE MODIFY)
允许其他事务共享修改对象,允许其他事务共享访问对象,使用IX方式封锁
4)共享访问(SHARE ACCESS)
允许其他事务共享修改对象,允许其他事务共享访问对象,使用IS方式封锁
5.3显示的锁定表
用户可以根据自己的需要显式的对表对象进行封锁。
LOCK TABLE <table_name> IN <lock_mode> MODE [NOWAIT];
lock_mode 是锁定的模式,可以选择的模式有 INTENT SHARE(意向共享)、INTENT EXCLUSIVE(意向排他)、SHARE(共享)和 EXCLUSIVE(排他)。
- 意向共享:不允许其他事务独占修改该表。意向共享锁定后,不同事务可以同时增、删、改、查该表的数据,也支持在该表上创建索引,但不支持修改该表的定义;
- 意向排他:不允许其他事务独占访问和独占修改该表。被意向排他后,不同事务可以同时增、删、改、查该表的数据,不支持在该表上创建索引,也不支持修改该表定义;
- 共享:只允许其他事务共享访问该表,仅允许其他事务查询表中的数据,但不允许增、删、改该表的数据;
- 排他:以独占访问方式锁定整个表,不允许其他事务访问该表,是封锁力度最大的一种封锁方式。
当使用 NOWAIT 时,若不能立即上锁成功则立刻返回报错信息,不再等待。
5.4查看锁
通过V$LOCK动态性能视图查看。
SQL> select * from v$lock;
ADDR :锁的内存地址;
TRX_ID:锁所属的事务ID;
LTYPE:锁的类型,可能是 OBJECT(对象锁)或者 TID(TID 锁);
LMODE:的模式,可能的取值有 S(共享锁)、X(排他锁)、IS(意向共享锁)、IX(意向排他锁);
BLOCKED:锁是否处于上锁等待状态,0 表示已上锁成功,1 表示处于上锁等待状态;
TABLE_ID:对于对象锁,表示表对象或字典对象的ID,对于TID锁,表示封锁记录对应的表ID;
ROW_IDX:TID 锁封锁记录的行信息;
TID:TID 锁对象事务 ID。
6、事务隔离级别
DM允许用户在SELECT语句的末尾加上 WITH UR 以指定当前查询语句的隔离级为读未提交,即允许脏读,并在该语句结束时自动恢复为原来的隔离级。
6.1数据读类型
6.1.1脏读(dirtyread)
一个事务正在对一条记录做修改,在这个事务完成并提交之前,这条数据是处于待定状态的(可能提交也可能回滚),这时,第二个事务来读取这条没有提交的数据,并据此做进一步的处理,就会产生未提交的数据依赖关系,这种现象被称为脏读。如果一个事务在提交操作结果之前,另一个事务可以看到该结果,就会发生脏读。
6.1.2不可重复读(non-repeatableread)
一个事务先后读取同一条记录,但两次读取的数据不同,称之为不可重复读。如果一个事务在读取了一条记录后,另一个事务修改了这条记录并且提交了事务,再次读取记录时如果获取到的是修改后的数据,这就发生了不可重复读情况。
6.1.3幻读(phantomread)
一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为幻读。
在 SQL-92 标准中,定义了四种隔离级别:读未提交、读提交、可重复读和串行化。每种隔离级别下对于读数据有不同的要求。
DM数据库支持三种事务隔离级别:读未提交、读提交和串行化。其中,读提交是DM数据库默认使用的事务隔离级别。可重复读升级为更严格的串行化隔离级。
6.2读提交隔离级别
DM 数据库的读提交隔离可以确保只访问到已提交事务修改的数据,保证数据处于一致 性状态,能够满足大多数应用的要求,并最大限度的保证系统并发性能,但可能会出现不可重复读取和幻读。
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
6.3串行化隔离级别
在要求消除不可重复读取或幻读的情况下,我们可以设置事务隔离级为串行化。跟读提交隔离级相比,串行化事务的查询本身不会增加任何代价,但修改数据可能引发“串行化事务被打断”错误。
当一个串行化事务试图更新或删除数据时,而这些数据在此事务开始后被其 他事务修改并提交时,DM 数据库将报“串行化事务被打断”错误。应用开发者应该充分考虑串行化事务带来的回滚及重做事务的开销,从应用逻辑上避免对相同数据行的激烈竞争导致产生大量事务回滚。并结合应用逻辑,捕获“串行化事务被打断”错误,进行事务重做等相应处理。如果系统中存在长时间运行的写事务,并且该长事务所操作的数据还会被其他短事务频繁更新的话,最好避免使用串行化事务。
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
6.4读未提交隔离级别
读未提交隔离级别是最不严格的隔离级别。实际上,在使用这个隔离级别时,有可能发生脏读、不可重复读和幻像。一般来说,读未提交隔离级别通常只用于访问只读表和只读视图,以消除可见性判断带来的系统开销,提升查询性能。
SET TRANSACTION ISOLATION LEVEL UNCOMMITTED;
6.5只读事务
DM 数据库还支持只读事务,只读事务只能访问数据,但不能修改数据。并且只读事务不会改变事务原有的隔离级。
SET TRANSACTION READ ONLY;
更多内容请参考:https://eco.dameng.com