数据库事务 原子性和隔离性的疑问 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
chaleaochexist
V2EX    数据库

数据库事务 原子性和隔离性的疑问

  •  
  •   chaleaochexist 2022-08-08 12:59:43 +08:00 2180 次点击
    这是一个创建于 1165 天前的主题,其中的信息可能已经有所发展或是发生改变。
    请教问题
    我现在有一个需求, 先清空一张表, 然后在同一场表 插入数据若干条

    如果我用事务约束. 是否会有某个时刻, 读了一张空表?

    事务的原子性是否指: "执行若干条 sql, 是原子的?"

    在这里事务的隔离性如何体现? 可重复读 好像解决不了这个问题?
    14 条回复    2022-08-11 15:04:45 +08:00
    fkdog
        1
    fkdog  
       2022-08-08 13:14:26 +08:00   1
    RC 级别,一个事务里每次 select 可以获取到其他事务已经提交的数据。
    RR 级别,一个事务里每次 select 获取的数据都是快照,可以重复读。
    update 、delete 、select .... for update 里 where 后边的查询都是取得当前读,也就是最新的数据。

    我觉得你的困惑是,RC 级别下,可以读取其他事务已经提交的数据是不是违反了数据库的隔离性。
    其实数据库的隔离性不是 100%完全隔离的,规范里定了 4 中隔离级别,根据自己的业务需求和使用场景来选择。
    实际上大部分的需求都是可以通过乐观锁、悲观锁等手段来实现数据隔离。
    tairan2006
        2
    tairan2006  
       2022-08-08 13:27:57 +08:00   1
    我觉得这里的问题其实是,你清空 db 用的是`delete from`还是`truncate`语句,后者在某些 db 里是不能放在事务里的,它会导致事务立刻提交。

    如果确认可以放在事务里,那么另外一个读取的事务是不可能读到空表的,无论是 RR 还是 RC 。
    7911364440
        3
    7911364440  
       2022-08-08 13:47:23 +08:00   1
    delete 语句会加行锁的,如果是 delete from t 会对所有行加锁,这个时候读操作应该会被阻塞吧,所以应该不会读到空表。
    nothingistrue
        4
    nothingistrue  
       2022-08-08 13:54:21 +08:00   1
    原子性是针对当前事务的多个语句的,要么全部执行要么全部不执行,对于当前事务的多个语句执行过程中,是否有其他事务也在执行,它不管,即使是执行的同一条数据。隔离性是针对修改同一个地方数据的不同事务的,不同的隔离级别有不同的表现,最高的序列隔离级别,能保证同一条数据当前只能被最多一个事务读写。

    当你是查询和修改已存在数据的时候,可重复读级别就能保证不发生并发不一致问题。但如果是查询和新增数据(比如值为 max + 1 的列)的时候,即使是最高级别的序列隔离性,也不能保证绝不发生并发不一致,因为这时候要想并发一致就得锁表,但为了性能基本上不会物理锁表只能是变通锁表,这个变通锁表就容易漏掉一些场景。

    对于你的需求,事务是解决不了并发不一致的。既然你要清空表了,那么最简单的实现就是手动锁表。
    yjhatfdu2
        5
    yjhatfdu2  
       2022-08-08 14:21:43 +08:00   1
    如果用的是 truncate ,那么有可能读到空表,因为 truncate 一般不支持事务。
    如果使用的是 read uncommitted ( mysql 下是这样,pg 下不会),也可能是读到空表
    其他情况不应该读到空表
    CRVV
        6
    CRVV  
       2022-08-08 14:41:49 +08:00   1
    > 事务的原子性是否指: "执行若干条 sql, 是原子的?"

    这个问题问得,原子性是不是指它是原子的。等于没问。
    原子性是指执行若干条 SQL 只能都成功或者都不成功。


    > 如果我用事务约束. 是否会有某个时刻, 读了一张空表?

    如果 START TRANSACTION; DELETE FROM table; INSERT INTO table VALUES..; COMMIT;
    那么空表的状态没有 commit. 如果你用的是 Read uncommitted ,就有可能读到,否则不会。
    chaleaochexist
        7
    chaleaochexist  
    OP
       2022-08-08 14:51:40 +08:00
    @CRVV 你说的和 4 楼有点不一致.

    代码里的原子是指不会被中断.

    sql 在一个事务中, 插入五条数据. 有没有可能某个瞬间实际插入了四条数据? 幻读是不是就是这个意思?
    chaleaochexist
        8
    chaleaochexist  
    OP
       2022-08-08 14:52:54 +08:00
    @nothingistrue 谢谢回复.学到很多.
    序列隔离级别 难道不是锁表吗? 事务按照顺序执行.也就是说同时只有一个事务在执行.
    exonuclease
        9
    exonuclease  
       2022-08-08 15:27:02 +08:00   1
    @chaleaochexist 在 Read Committed 级别或者以上是不可能的 插入五条数据还没提交以前对别的事务不可见
    yjhatfdu2
        10
    yjhatfdu2  
       2022-08-08 15:32:59 +08:00   1
    @chaleaochexist pg 下,序列化隔离等级,也不会锁表,依然是读写无冲突,但是会带来额外开销,降低性能。其他常用数据库不支持序列化隔离等级
    yjhatfdu2
        11
    yjhatfdu2  
       2022-08-08 15:34:37 +08:00   1
    建议把 pg 的隔离等级文档看一下,就比较清楚了 http://www.postgres.cn/docs/12/transaction-iso.html
    CRVV
        12
    CRVV  
       2022-08-08 16:22:10 +08:00   1
    @chaleaochexist

    这些事情自己开两个 session 试一下就知道了,有现成的代码,https://github.com/ept/hermiage
    nothingistrue
        13
    nothingistrue  
       2022-08-09 09:27:59 +08:00   1
    @chaleaochexist #8 不是同时只有一个事务在执行,而是针对一个数据主体同时只有一个事务在执行。如果操作不涉及插入行,那么数据主体通常是已存在的行,这时候只锁行就行了。如果操作涉及插入行,那么数据主体理论上是全表,但实际上可能不是,因为锁表开销太大了,这方面各数据库都有自己的实现。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3202 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 11:29 PVG 19:29 LAX 04:29 JFK 07:29
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86