收藏

第七十五章 SQL命令 START TRANSACTION

2021-11-14  本文已影响0人  Cache技术分享

第七十五章 SQL命令 START TRANSACTION

开始一个事务。

大纲

START TRANSACTION [%COMMITMODE commitmode]

START TRANSACTION [transactionmodes]

参数

描述

START TRANSACTION语句启动一个事务。
START TRANSACTION立即启动一个事务,而不管当前的提交模式设置如何。
无论当前的提交模式设置如何,以START transaction开始的事务必须通过发出显式COMMITROLLBACK来结束。

START TRANSACTION是可选的。

START TRANSACTION启动一个事务时,它将$TLEVEL事务级别计数器从0增加到1,表明事务正在进行。
还可以通过检查%INTRANSACTION语句设置的SQLCODE来确定事务是否在进行中。
当事务正在进行时发出START TRANSACTION$TLEVEL%INTRANSACTION没有影响。

SQL不支持嵌套事务。
当事务已经在进行时发出START TRANSACTION不会启动另一个事务,也不会返回错误代码。 SQL支持保存点,允许事务的部分回滚。

当发出SAVEPOINT语句时,如果事务没有在进行中,则SAVEPOINT将启动一个事务。
但是,不推荐使用这种方式启动事务。

如果事务操作未能成功完成,则会发出SQLCODE -400

设置参数

可以选择使用START TRANSACTION来设置参数。
设置的参数立即生效。
但是,无论如何设置commitmode参数,任何以START transaction启动的事务都必须以显式COMMITROLLBACK结束。
参数设置在当前进程期间继续有效,直到显式重置为止。
它们不会在事务结束时自动重置为默认值。

单个START TRANSACTION语句可用于设置提交模式参数或事务模式参数,但不能同时设置两者。
要设置两者,可以发出set TRANSACTIONSTART TRANSACTION,或者两条START TRANSACTION语句。
只有第一个START TRANSACTION才会启动一个事务。

在发出START TRANSACTION之后,可以在事务期间通过发出另一个START TRANSACTIONSET TRANSACTION或方法调用来更改这些参数设置。
更改commitmode参数并不会删除使用显式COMMITROLLBACK结束当前事务的需求。

可以使用SET TRANSACTION语句来设置提交模式或事务模式参数,而不需要启动事务。
还可以使用方法调用在事务外部或事务内部设置这些参数。

%COMMITMODE

%COMMITMODE关键字允许为当前流程指定自动事务启动和承诺行为。
START TRANSACTION %COMMITMODE更改当前流程中所有未来事务的提交模式设置。
它不会影响由START transaction语句发起的事务。
无论当前或设置提交模式,START TRANSACTION都会立即启动一个事务,并且这个事务必须通过发出显式的commitROLLBACK来结束。

可用的%COMMITMODE选项有:

TRUNCATE TABLE不会在自动启动的事务中发生。
如果需要对TRUNCATE TABLE进行日志记录和回滚,则必须显式指定START TRANSACTION,并以显式COMMITrollback结束。

可以使用SetOption()方法在ObjectScript中设置%COMMITMODE,如下set status=$SYSTEM.SQL.Util.SetOption("AutoCommit",intval,.oldval)
可用的方法值为0 (NONE)、1 (IMPLICIT)和2 (EXPLICIT)。

注意:分片表总是处于No AutoCommit模式(SetOption("AutoCommit",0)),这意味着所有对分片表的插入、更新和删除都是在事务范围之外执行的。

隔离级别

可以为发出查询的进程指定“隔离级别”。
“隔离级别”选项允指定正在进行的更改是否可用于查询的读访问。
如果另一个并发进程正在执行对表的插入或更新,并且对表的更改在事务中,那么这些更改正在进行中,并且可能会回滚。
通过为正在查询该表的流程设置ISOLATION LEVEL,可以指定是否希望在查询结果中包含或排除这些正在进行的更改。

READ UNCOMMITTED还是READ VERIFIED?

下面的例子演示了READ UNCOMMITTEDREAD VERIFIED之间的区别:

SELECT Name,SSN FROM Sample.Person WHERE Name >= 'M' 

查询优化器可能首先选择从Name索引中收集所有RowID包含的符合>= 'M'条件的Name
收集之后,每次访问一个RowID,以检索NameSSN字段用于输出。
并发运行的更新事务可以将一个RowID 72PersonName字段从“Smith”更改为“Abel”,该字段位于查询的rowwid集合和它对表的逐行访问之间。
在本例中,索引中的RowID集合将包含不再符合Name >= 'M'条件的行的RowID

READ UNCOMMITTED查询处理假设Name >= 'M'条件已经被索引满足,并且将输出从索引中收集的每个RowID在表中出现的任何Name
因此,在本例中,它将输出一个名称为'Abel'的行,该行不满足条件。

READ VERIFIED查询处理注意到,它正在从表中为output (Name)检索一个字段,该字段参与了之前应该由索引满足的条件,然后重新检查条件,以防在检查索引之后字段值发生变化。
在重新检查时,它注意到该行不再满足条件,并将其从输出中删除。
只有输出所需的值才会重新检查其条件:在本例中,SELECT SSN FROM Person WHERE Name >= 'M'将输出RowID为72的行。

READ COMMITTED异常

ISOLATION LEVEL read committed生效时,可以通过设置ISOLATION LEVEL read committed或SetOption()方法,如下SET status=$SYSTEM.SQL.Util.SetOption("IsolationMode",1,.oldval)
SQL只能检索已提交数据的更改。
然而,也有一些明显的例外:

注意:在使用ECP(企业缓存协议)的 IRIS实现上,与READ UNCOMMITTED相比,使用READ COMMITTED可能会导致明显的性能下降。
在定义包含ECP的事务时,开发人员应该权衡READ UNCOMMITTED的优越性能和READ COMMITTED的更高数据准确性。

有效隔离级别

可以使用set TRANSACTION(不启动事务)、START TRANSACTION(设置隔离模式并启动事务)或SetOption(“IsolationMode”)方法调用为进程设置隔离级别。

指定的隔离级别保持有效,直到由SET TRANSACTIONSTART TRANSACTIONSetOption(“IsolationMode”)方法调用显式重置。
由于COMMITROLLBACK仅对数据更改有意义,而对数据查询没有意义,因此COMMITROLLBACK操作对ISOLATION LEVEL设置没有影响。

在查询开始时有效的“隔离级别”在查询期间仍然有效。

可以使用GetOption(“IsolationMode”)方法调用确定当前进程的隔离级别。
还可以使用SetOption(“IsolationMode”)方法调用为当前进程设置隔离模式。
这些方法将READ UNCOMMITTED(默认值)指定为0,READ COMMITTED指定为1,READ VERIFIED指定为3
指定任何其他数值将保持隔离模式不变。
如果将隔离模式设置为当前隔离模式,则不会发生错误或更改。
以下示例显示了这些方法的使用:

ClassMethod SetTransaction1()
{
    w $SYSTEM.SQL.GetOption("IsolationMode")," 默认",!
    &sql(
        START TRANSACTION ISOLATION LEVEL READ COMMITTED,READ WRITE
    )
    w $SYSTEM.SQL.GetOption("IsolationMode")," TART TRANSACTION之后",!
    d $SYSTEM.SQL.SetOption("IsolationMode",0,.stat)
    if stat=1 {
        w $SYSTEM.SQL.GetOption("IsolationMode")," after IsolationMode=0 call",! 
    } else { WRITE "Set IsolationMode error" 
    }
    &sql(COMMIT)
}

隔离模式和访问模式必须始终兼容。
更改访问模式将更改隔离模式,示例如下:

ClassMethod SetTransaction2()
{
    w $SYSTEM.SQL.GetOption("IsolationMode")," default",!
    &sql(
        SET TRANSACTION ISOLATION LEVEL READ COMMITTED,READ WRITE
    )
    w $SYSTEM.SQL.GetOption("IsolationMode")," after SET TRANSACTION",!
    &sql(START TRANSACTION READ ONLY)
    w $SYSTEM.SQL.GetOption("IsolationMode")," after changing access mode",!
    &sql(COMMIT)
}

ObjectScript和SQL事务

ObjectScript和SQL事务命令是完全兼容和可互换的,但有以下例外:

如果当前没有事务,ObjectScript TSTARTSQL START TRANSACTION都会启动一个事务。
但是,START TRANSACTION不支持嵌套事务。
因此,如果需要(或可能需要)嵌套事务,最好使用TSTART启动事务。
如果需要与SQL标准兼容,请使用START TRANSACTION

ObjectScript事务处理为嵌套事务提供了有限的支持。
SQL事务处理为事务中的保存点提供支持。

如果事务涉及SQL数据修改语句,则应该使用SQL START transaction语句启动事务,并使用SQL COMMIT语句提交事务。
(这些语句可以是显式的,也可以是隐式的,具体取决于%COMMITMODE设置。)
使用TSTART/TCOMMIT嵌套的方法可以包含在事务中,只要它们不初始化事务。
方法和存储过程通常不应该使用SQL事务控制语句,除非按照设计,它们是事务的主控制器。
存储过程通常不应该使用SQL事务控制语句,因为这些存储过程通常是从ODBC/JDBC调用的,ODBC/JDBC有自己的事务控制模型。

示例

下面的嵌入式SQL示例使用两个START TRANSACTION语句来启动事务并设置其参数。
注意,第一个START TRANSACTION启动一个事务,设置提交模式并增加$TLEVEL事务级别计数器。
第二个START TRANSACTION为当前事务中的查询读操作设置隔离模式,但不增加TLEVEL,因为事务已经启动。 `SAVEPOINT`语句增加`TLEVEL`:

ClassMethod StartTransaction()
{
    &sql(SET TRANSACTION %COMMITMODE EXPLICIT)
    w !,"设置事务提交模式, SQLCODE=",SQLCODE
    w !,"事务级别=",$TLEVEL
    &sql(SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED)
    w !,"设置事务隔离模式, SQLCODE=",SQLCODE
    w !,"事务级别=",$TLEVEL
    &sql(START TRANSACTION)
    w !,"开始事务, SQLCODE=",SQLCODE
    w !,"事务级别==",$TLEVEL
    &sql(SAVEPOINT a)
    w !,"设置保存点, SQLCODE=",SQLCODE
    w !,"事务级别==",$TLEVEL
    &sql(COMMIT)
    w !,"提交事务, SQLCODE=",SQLCODE
    w !,"事务级别==",$TLEVEL
}
上一篇 下一篇

猜你喜欢

热点阅读