Mysql 何时使用选择。。。更新?

Mysql 何时使用选择。。。更新?,mysql,sql,sql-server,transactions,select-for-update,Mysql,Sql,Sql Server,Transactions,Select For Update,请帮助我理解SELECT后面的用例。。。用于更新 问题1:以下是选择时的一个好例子。。。对于更新,是否应使用 鉴于: 房间[id] 标签[id,名称] 房间标签[房间id,标签id] 房间id和标签id是外键 应用程序希望列出所有房间及其标记,但需要区分没有标记的房间和已删除的房间。如果选择。。。如果未使用更新,可能发生的情况是: 最初: 房间包含[id=1] 标签包含[id=1,name='cats'] 房间标签包含[房间id=1,标签id=1] 线程1:从房间中选择id

请帮助我理解
SELECT后面的用例。。。用于更新

问题1:以下是
选择时的一个好例子。。。对于更新,是否应使用

鉴于:

  • 房间[id]
  • 标签[id,名称]
  • 房间标签[房间id,标签id]
    • 房间id和标签id是外键
应用程序希望列出所有房间及其标记,但需要区分没有标记的房间和已删除的房间。如果选择。。。如果未使用更新,可能发生的情况是:

  • 最初:
    • 房间包含
      [id=1]
    • 标签包含
      [id=1,name='cats']
    • 房间标签包含
      [房间id=1,标签id=1]
  • 线程1:
    从房间中选择id
    
    • 返回[id=1]
  • 线程2:
    从房间id=1的房间标签中删除
  • 线程2:
    从id=1的房间中删除
  • 线程2:[提交事务]
  • 线程1:
    从房间标记中选择tags.name,其中房间标记为.room\u id=1,标记为.id=room\u tags.tag\u id
    
    • 返回一个空列表
现在线程1认为房间1没有标签,但实际上房间已被移除。为了解决这个问题,线程1应该
从文件室中选择id进行更新
,从而防止线程2在线程1完成之前从
文件室
中删除。对吗

问题2:什么时候应该使用
SERIALIZABLE
事务隔离与
READ\u COMMITTED
选择。。。是否要更新


答案应该是可移植的(不是特定于数据库的)。如果无法做到这一点,请解释原因。

实现文件室和标签之间的一致性并确保文件室在删除后永不返回的唯一便携式方法是使用
选择更新
锁定文件室

然而,在某些系统中,锁定是并发控制的一个副作用,您可以在不明确指定更新的
的情况下获得相同的结果


为了解决这个问题,线程1应该
从文件室中选择id进行更新
,从而防止线程2在线程1完成之前从
文件室
中删除。对吗

这取决于数据库系统使用的并发控制

  • MySQL
    中的
    MyISAM
    (以及其他一些旧系统)会在查询期间锁定整个表

  • SQL Server
    中,
    SELECT
    查询将共享锁放置在它们所检查的记录/页面/表上,而
    DML
    查询将放置更新锁(稍后将升级为独占锁或降级为共享锁)。独占锁与共享锁不兼容,因此
    SELECT
    DELETE
    查询将锁定,直到提交另一个会话

  • 在使用
    MVCC
    (如
    Oracle
    PostgreSQL
    MySQL
    InnoDB
    )的数据库中,
    DML
    查询创建记录副本(以一种或另一种方式),通常读卡器不会阻止写入程序,反之亦然。对于这些数据库,
    SELECT For UPDATE
    很方便:它将锁定
    SELECT
    DELETE
    查询,直到另一个会话提交,就像
    SQL Server
    一样

什么时候应该使用
REPEATABLE\u READ
事务隔离,而不是
READ\u COMMITTED
选择。。。是否要更新

通常,
REPEATABLE READ
不禁止虚行(在另一个事务中出现或消失的行,而不是被修改的行)

  • Oracle
    和更早的
    PostgreSQL
    版本中,
    REPEATABLE READ
    实际上是
    SERIALIZABLE
    的同义词。基本上,这意味着事务在启动后不会看到所做的更改。因此,在这个设置中,最后一个
    线程1
    查询将返回房间,就像它从未被删除一样(这可能是您想要的,也可能不是您想要的)。如果不想在删除房间后显示这些房间,则应使用
    SELECT FOR UPDATE

  • InnoDB
    中,
    REPEATABLE READ
    SERIALIZABLE
    是不同的事情:处于
    SERIALIZABLE
    模式的读卡器在其评估的记录上设置next key锁,有效地防止并发
    DML
    。因此,您不需要在可串行化模式下选择
    进行更新
    ,但需要在
    可重复读取
    已提交读取
    中进行更新

请注意,关于隔离模式的标准确实规定,您在查询中看不到某些怪癖,但没有定义如何使用(使用锁定或
MVCC
或其他方式)

当我说“您不需要选择更新”时,我真的应该加上“因为某些数据库引擎实现的副作用”。

简短回答:

问题1:是的

问题2:你用哪一种并不重要

长答覆:


A
选择。。。对于“更新”
(顾名思义),将选择某些行,但也会锁定它们,就像它们已经被当前事务更新一样(或者就像已经执行了身份更新一样)。这允许您在当前事务中再次更新它们,然后提交,而另一个事务不能以任何方式修改这些行

从另一个角度来看,似乎以下两条语句是以原子方式执行的:

select * from my_table where my_condition;

update my_table set my_column = my_column where my_condition;
由于受
my_条件影响的行被锁定,其他事务无法以任何方式修改它们,因此,事务隔离级别与