在事务内部和外部执行SELECT语句有什么区别吗?

57

默认的READ COMMITTED隔离级别是否会使得在事务内部的SELECT语句与不在事务中的语句不同?

我正在使用MS SQL

4个回答

87

是的,在事务内部的语句可以看到其他先前的插入/更新/删除语句所做的更改;在事务外的选择语句则不能。

如果你只是询问隔离级别的作用,那么请注意所有选择语句(以及所有其他类型的语句)都处于一个事务中。唯一的区别是:显式在一个事务中执行的语句和独立执行的语句之间,前者会在执行之前立即开始其事务,并在执行之后立即提交或回滚;

而显式在事务中的语句可以(因为它有一个"Begin Transaction"语句)在同一事务中发生其他语句(插入/更新/删除等),并且可以在该语句之前或之后发生。

因此,无论隔离级别设置为何值,两个选择语句(显式事务内部或显式事务外部)仍将位于该隔离级别下运行的事务中。

附加说明:以下内容适用于SQL Server,但所有数据库必须以相同方式工作。在SQL Server中,查询处理器始终处于三个事务模式之一:自动提交隐式显式

  • 自动提交是SQL Server数据库引擎的默认事务管理模式。.. 当每个Transact-SQL语句完成时,它都被提交或回滚... 如果语句成功完成,则提交;如果遇到任何错误,则回滚。这是默认设置,也是评论中@Alex提出的问题的答案。

  • 隐式事务模式下,"…… SQL Server 数据库引擎会在当前事务提交或回滚后自动开始新的事务。您不需要指定事务的开始,只需提交或回滚每个事务。隐式事务模式生成连续的事务链。"请注意,斜体部分适用于每个事务,无论是单一还是多语句事务。

  • 当您使用 BEGIN TRANSACTION 语句显式启动一个事务时,引擎处于显式事务模式。然后,在该事务中执行每个语句,直到您显式终止事务(使用COMMITROLLBACK)或发生导致引擎终止和回滚的故障。


  • 1
    我认为他在问:“select ...”和“start transaction; select ...; stop transaction;”之间是否有区别。 - tster
    我知道你写下那个答案已经有一段时间了,但是你能否给我提供一个解释“所有的Select语句都在一个事务中”的来源呢?我在互联网上找不到任何相关信息,但是一直看到这样的说法。谢谢! - Alex Endris
    1
    @Alex,请看我在答案文本中添加的内容。 - Charles Bretana
    @CharlesBretana - 你能提供任何支持你的说法的文档链接吗:是的,在事务内部可以看到由该事务中其他先前的Insert/Update/delete语句所做的更改;在事务之外的Select语句则不能。 - Shuzheng

    7

    是的,有一些区别。对于MySQL数据库,在第一次查询之前,数据库实际上不会启动快照。因此,重要的不是开始,而是事务内的第一条语句。如果我执行以下操作:

    #Session 1
    begin; select * from table;
    
    #Session 2
    delete * from table; #implicit autocommit
    
    #Session 1
    select * from table;
    

    那么在第一次和第二次的会话中,我将得到相同的东西(在我删除它之前表格里的信息)。当我结束第一次的事务(提交,开始或回滚)并再次从该会话中检查时,该表将显示为空。


    1
    对于MySQL InnoDB,你是完全正确的 - 对于InnoDB READ COMMITTED隔离模式可以保证一致性读取。然而,在一般情况下,你可能会遇到不可重复读取的情况,这种情况下,无论是自动提交还是挂起事务,都能看到其他事务所做的修改,前提是这些更改已经提交。 - Roland Bouman

    3

    READ COMMITTED隔离级别与已写入的记录有关,与此select语句是否在事务中无关(除了在同一事务中写入的内容)。


    3

    如果您的数据库(或在mysql中,所有用于select语句的表的底层存储引擎)是事务性的,那么就没有办法在“事务之外”执行它。

    也许您想要“在自动提交模式下运行”,但这并不等同于“非事务性”。在后一种情况下,它仍然在事务中运行,只是在完成您的语句后立即结束事务。

    因此,在这两种情况下,运行期间,单个select语句将从其他事务中以READ COMMITTED级别隔离。

    现在,对于您的READ COMMITTED事务隔离级别,这意味着令人惊讶的是:并没有太多影响。

    READ COMMITTED表示您可能会遇到不可重复读取的情况:当在同一事务中运行多个select语句时,可能会发生您在某个时间点选择的行被另一个事务修改和提交的情况。当您在同一待处理事务中稍后重新执行select语句时,您将能够看到这些更改。在自动提交模式下,这两个select语句将在其自己的事务中执行。如果另一个事务已经修改并提交了您第一次选择的行,那么当您第二次执行该语句时,您也将能够看到这些更改。


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接