oracle 幻读, 不可重复读是如何避免的? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
stach
V2EX    数据库

oracle 幻读, 不可重复读是如何避免的?

  •  
  •   stach 2021-09-06 15:52:52 +08:00 1967 次点击
    这是一个创建于 1497 天前的主题,其中的信息可能已经有所发展或是发生改变。

    lz 经常在 v 站评论帮助他人, 很少发帖, 这次借贵宝地, 请教路过的各位大佬谈谈看法, 解答一下疑惑:

    oracle 在具体实践中是否会考虑 "不可重复读", "幻读" 问题, 又是如何去解决的呢?


    下面是楼主做的准备工作:

    • 事务的隔离级别

      • MySQL(InnoDB)
        • 默认事务隔离级别是 REPEATABLE-READ(可重复读)
      • oracle
        • 默认的事务隔离级别是 READ COMMITTED(读提交)
    • 存在的问题

      • MySQL 存在 "幻读" 问题
      • oracle 存在 "不可重复读" "幻读" 问题
    • 解决方法

      • MySQL 使用 Next-Key Lock(锁定一个范围,并锁定记录本身), 具体表现就是在事务内查询时 select... for update
      • oracle 暂时没看到具体实践的资料

    楼主查过 oracle 官网的文档, 似乎也没有具体的答案, db2 的资料多一些, 直接修改隔离级别为 "序列化读" 也不现实.

    6 条回复    2021-09-11 01:21:29 +08:00
    sun1991
        1
    sun1991  
       2021-09-06 16:39:00 +08:00
    给个具体点的例子吧?
    stach
        2
    stach  
    OP
       2021-09-06 17:01:17 +08:00
    @sun1991

    这里有个 MySQL 的例子: https://segmentfault.com/a/1190000016566788, 我这里是没有 oracle 的.
    lz 是互联网从业者, 几乎都使用 MySQL 数据库, 所以疑惑 oracle 从业者的实践姿势
    stach
        3
    stach  
    OP
       2021-09-06 19:27:21 +08:00
    可能 v 站大多是用 MySQL 的兄弟吧, 这个问题石沉大海了 :(
    sun1991
        4
    sun1991  
       2021-09-07 09:42:32 +08:00   1
    以下是我的个人理解:

    Oracle 一共只有两种隔离级别 (抛开 readonly 不谈). Serialize 一般不用. 常用的也就是 read committed.

    Oracle 的锁是加在物理 row 上面, 也就是说, 如果 row 不存在, 那么就不能加锁. 所以 Oracle 没有 MySQL 那么多的弯弯绕. 如果你要应对不可重复读, 幻读问题, 那么老老实实地用 serialize 隔离级别.

    Oracle 的 serialize 隔离级别其实是一种乐观锁, 它限制的是自己的 session 而非其它 session 的写操作, 意思是当检测到自己 session 违反了 serialize 隔离级别的限制, 就报错.

    总之, Oracle 的优化目标是尽可能使得所有的 read 操作尽快完成, 所以能不锁的一概不锁.
    stach
        5
    stach  
    OP
       2021-09-07 10:33:38 +08:00
    @sun1991
    赞同老哥的说法, 不能用 MySQL 的理论去套 oracle, 开启事务的时候设定隔离级别为 serialize 不失为解决 不可重复读, 幻读的好方法.

    其实 MySQL 官方的 Python Connector 库开启事务的时候, 就有指定隔离级别的参数, 只是我们几乎都习惯了固定为 REPEATABLE READ.

    ```python
    def start_transaction(self, consistent_snapshot=False,
    isolation_level=None, readOnly=None):
    """Start a transaction

    This method explicitly starts a transaction sending the
    START TRANSACTION statement to the MySQL server. You can optionally
    set whether there should be a consistent snapshot, which
    isolation level you need or which access mode i.e. READ ONLY or
    READ WRITE.

    For example, to start a transaction with isolation level SERIALIZABLE,
    you would do the following:
    >>> cnx = mysql.connector.connect(..)
    >>> cnx.start_transaction(isolation_level='SERIALIZABLE')

    Raises ProgrammingError when a transaction is already in progress
    and when ValueError when isolation_level specifies an Unknown
    level.
    """
    ```
    Hozzz
        6
    Hozzz  
       2021-09-11 01:21:29 +08:00   1
    select for update
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1066 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 34ms UTC 23:19 PVG 07:19 LAX 16:19 JFK 19:19
    Do have faith in what you're doing.
    ubao 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