第七十五章 SQL命令 START TRANSACTION

第七十五章 SQL命令 START TRANSACTION

开始一个事务。

大纲

START TRANSACTION [%COMMITMODE commitmode]

START TRANSACTION [transactionmodes]

参数

  • commitmode - 可选-指定在当前进程中如何向数据库提交将来的事务。
    取值包括EXPLICITIMPLICITNONE
    默认是维护现有的提交模式;
    进程的初始提交模式默认值是IMPLICIT
  • transactionmodes - 可选—指定事务的隔离模式和访问模式。
    可以将隔离模式、访问模式或这两种模式的值指定为逗号分隔的列表。隔离模式的有效值为ISOLATION LEVEL READ COMMITTED, ISOLATION LEVEL READ UNCOMMITTED, ISOLATION LEVEL READ VERIFIED. 默认 ISOLATION LEVEL READ UNCOMMITTED.访问模式的有效值为“READ ONLY”“READ WRITE”
    注意,只有隔离级别READ COMMITTED与读写模式READ WRITE兼容。

描述

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

START TRANSACTION是可选的。

  • 如果流程只查询数据(SELECT语句),可以使用SET TRANSACTION来建立隔离级别。
    不需要START TRANSACTION
  • 如果进程正在修改数据,那么是否需要通过发出START transaction来显式地开始SQL事务,这取决于进程的当前提交模式设置(也称为AutoCommit设置)。
    如果当前进程的提交模式是隐式的或显式的,则发出START TRANSACTION是可选的。
    如果忽略START TRANSACTION,则在调用修改数据操作(DELETEUPDATEINSERT)时,系统会自动启动一个事务。
    如果指定START TRANSACTION,则会立即启动一个事务,并且必须通过显式COMMITROLLBACK来结束该事务。

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选项有:

  • IMPLICIT隐式:启用自动事务承诺(初始流程默认值)。
    当程序发出数据库修改操作(INSERTUPDATEDELETE)时,SQL自动启动一个事务。
    事务将继续进行,直到操作成功完成并SQL自动提交更改,或者操作无法在所有行上成功完成并SQL自动回滚整个操作。
    每个数据库操作(INSERTUPDATEDELETE)构成一个单独的事务。
    成功完成数据库操作将自动清除回滚日志、释放锁并减少$TLEVEL
    不需要COMMIT语句。
  • EXPLICIT:关闭自动事务承诺。
    当程序发出第一个数据库修改操作(INSERTUPDATEDELETE)时,SQL自动启动一个事务。
    该交易将继续进行,直到明确达成协议。
    成功完成后,发出COMMIT语句。
    如果数据库修改操作失败,则发出ROLLBACK语句将数据库恢复到事务开始之前的位置。
    EXPLICIT模式下,多个数据库修改操作可以组成一个事务。
  • NONE:没有自动事务处理。
    除非由START TRANSACTION显式调用,否则不会初始化事务。
    必须通过发出COMMITROLLBACK语句显式地结束所有事务。
    因此,事务中是否包含数据库操作以及事务中数据库操作的数量都是用户定义的。

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 UNCOMMITTED确保查询将在不等待并发插入或更新进程的情况下返回结果,并且不会因为锁定超时错误而失败。
    然而,READ UNCOMMITTED的结果可能包括未提交的值;
    这些值在内部可能不一致,因为插入或更新操作只部分完成,这些值可能随后被回滚。
    如果查询进程不在显式事务中,或者事务没有指定隔离级别,则READ UNCOMMITTED是默认值。
    READ UNCOMMITTEDREAD - WRITE访问不兼容;
    试图在同一语句中同时指定这两个变量会导致SQLCODE -92错误。
  • READ VERIFIED声明来自其他事务的未提交数据立即可用,并且不执行锁操作。
    这包括随后可能被回滚的更改。
    然而,与READ UNCOMMITTED不同的是,READ VERIFIED事务将重新检查任何可能因未提交或新提交的数据而失效的条件,这将导致不满足查询条件的输出。
    由于这种条件重新检查,READ VERIFIEDREAD UNCOMMITTED更准确,但效率更低,应该只在可能发生对条件检查的数据的并发更新时使用。
    READ VERIFIEDREAD - WRITE访问不兼容;
    试图在同一语句中同时指定这两个变量会导致SQLCODE -92错误。
  • READ COMMITTED表示只有那些已经提交的更改可以用于查询访问。
    这确保了在数据库上以一致的状态执行查询,而不是在进行一组更改时执行,这组更改随后可能会回滚。
    如果请求的数据已被更改,但更改尚未提交(或回滚),则查询将等待事务完成。
    如果在等待该数据可用时发生锁定超时,则会发出SQLCODE -114错误。

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只能检索已提交数据的更改。
然而,也有一些明显的例外:

  • 查询永远不会返回已删除的行,即使删除该行的事务正在进行,且删除可能随后回滚。
    ISOLATION LEVEL READ COMMITTED确保插入和更新处于一致状态,而不是删除。
  • 如果查询包含聚合函数,则聚合结果将返回数据的当前状态,而与指定的隔离级别无关。
    因此,聚合结果中包含正在进行的插入和更新(随后可能回滚)。
    正在进行的删除(随后可能会回滚)不包括在聚合结果中。
    这是因为聚合操作需要访问表中的许多行数据。
  • 包含DISTINCT子句或GROUP BY子句的SELECT查询不受隔离级别设置的影响。
    包含这些子句之一的查询将返回数据的当前状态,包括可能随后回滚的正在进行的更改。
    这是因为这些查询操作需要访问表中的许多行数据。
  • 带有%NOLOCK关键字的查询。

注意:在使用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
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容