V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
cevincheung
V2EX  ›  PostgreSQL

关于 PGSQL 的事物。

  •  
  •   cevincheung · 2016-01-02 02:34:41 +08:00 · 3014 次点击
    这是一个创建于 3233 天前的主题,其中的信息可能已经有所发展或是发生改变。

    PGSQL 的事物描述貌似是这样的:

    Balance: 100

    并发事物 A : update table set balance = balance -1 where id = 1 (Balance:99)
    并发事物 B : select balance from table where id = 1 (Balance: 100)

    这是不是不用事物更好…… - -#

    14 条回复    2016-01-04 09:55:34 +08:00
    lsylsy2
        1
    lsylsy2  
       2016-01-02 05:04:16 +08:00
    没看懂……首先是事务
    然后“事务”的意义是
    并发事物 A :
    update table set balance = 101 where id = 1
    select balance from table where id = 1

    并发事物 B :
    update table set balance = 99 where id = 1
    select balance from table where id = 1

    两个 select 的结果都等于自己那个事务 set 的那个值,不会出现“执行了 A 的 update ”-“执行了 B 的 update ”-“执行了 A 的 select ,得出 balance=99 的结果”这样的问题(这个例子好像不太体现事务的特征但是应该没有错误……大半夜的想不起来了)
    从这样的角度来讲,你的那个 B 读出 100 并没有问题,因为 A 和 B 是同时执行的,先执行完了 B (读出 100 )后执行 A (减一)没有任何问题。
    gamexg
        2
    gamexg  
       2016-01-02 08:28:57 +08:00 via Android
    手机不方便
    pg 文档,有各种事务级别详细的说明。包括优势和缺陷。
    tabris17
        3
    tabris17  
       2016-01-02 11:17:08 +08:00
    这就是事务隔离啊。大大的好处。怎么得出不用事务更好的结论的
    cevincheung
        4
    cevincheung  
    OP
       2016-01-02 13:01:46 +08:00
    @tabris17
    假设用户同时在进行购物和提现的操作。分别是两个事物,购物的事物帐户余额扣除了 N 元,提现要要提 X 元,结果前面的事物还没提交,后端 select 到的账户余额是购物扣除前的余额?
    lsylsy2
        5
    lsylsy2  
       2016-01-02 16:45:59 +08:00
    @cevincheung 就是这样,然后提现成功,购物扣款失败,很符合逻辑啊
    cevincheung
        6
    cevincheung  
    OP
       2016-01-02 20:06:35 +08:00
    @lsylsy2

    假设。

    事物 A 、 B 一个购买,一个提现。都是减钱的操作。

    账户余额剩余 100 元。
    A:消耗 1 元
    B:消耗 100 元

    A/B: BEGIN

    A:select balance from user where id = 1
    B:同 A

    此时两个事物获取的 balance 都是 100 。代码逻辑验证通过
    A:update user set balance = 99 where id = 1
    A:insert into orders 完成支付并订单入库
    B:update user set balance = 0 where id = 1

    A/B : commit

    期间也没有什么异常,是不是?
    cevincheung
        7
    cevincheung  
    OP
       2016-01-02 20:13:14 +08:00
    @lsylsy2
    更关键的是, PGSQL 的事物是这样的:

    A:begin
    A:update user set balance = 0
    B:begin
    A:commit
    B:select balance from user where id = 1 这个时候获取的 balance 不是 0 ?
    lsylsy2
        8
    lsylsy2  
       2016-01-02 20:22:00 +08:00
    @cevincheung 我不太熟 PG ……用其它 SQL 比如 mysql 不会这样么?
    首先是你第一个 at 我的内容:事务隔离如果设置成序列化或者可重复读的话,你的这两个 commit 都只会有一个成功,另一个会失败。
    第二个的话,会是两种情况:
    1 、读 0 , B commit 成功;
    2 、读不是 0 ( Acommit 之前的值),然后 Bcommit 失败。
    cevincheung
        9
    cevincheung  
    OP
       2016-01-02 20:56:52 +08:00
    @lsylsy2
    每次 begin 会分配一个事物 ID ,每个事物中的数据都是隔离的。

    从该 SELECT 查询开始执行时,在此查询执行期间,任何其它并发事物针对该查询结果集的数据操作都将不会被本次查询读到,即本次查询获取的数据版本是与查询开始执行时的数据版本相一致。

    可串行:
    从该 SELECT 查询所在事物开始时,在此查询执行期间,任何其它并发事物针对该查询结果集的数据操作都将不会被本次查询读到,即本次查询获取的数据版本是与查询所在事物开始时的数据版本相一致。
    ch3nz
        10
    ch3nz  
       2016-01-02 22:30:02 +08:00
    A,B 如果是两个的事务,那么是不会出问题的,因为锁表了,只有一个事务在跑.
    A,B 如果是两个加减钱的操作但是你放在一个事务里面并且不多加验证,跟拿刀捅自己并且问为什么流血了一样.

    BEGIN
    update user set balance = balance -1 where id = 1
    insert into orders
    SAVEPOINT save_order
    update user set balance = balance - 100 where id = 1
    //检查发现 balance 负数了
    ROLLBACK to save_order
    COMMIT
    cevincheung
        11
    cevincheung  
    OP
       2016-01-02 23:34:16 +08:00
    @ch3nz
    可是 pgsql 的事物好像是 如果开启了事物 1 , select 一条数据,事物 2 中如果 update ,事物 1 中再 select ,获取到的仍旧是以前(或当前事物的最新版本)的数据。
    gamexg
        12
    gamexg  
       2016-01-02 23:40:48 +08:00 via Android
    这就是正确的行为啊
    如果不这样事务 2 回滚了怎么办?

    看 pg 文档吧, 4 中事务级别很详细的介绍。
    gamexg
        13
    gamexg  
       2016-01-02 23:47:23 +08:00 via Android
    tabris17
        14
    tabris17  
       2016-01-04 09:55:34 +08:00
    @cevincheung 当然了,有什么问题,事务没提交就是没操作成功
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5436 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 35ms · UTC 06:54 · PVG 14:54 · LAX 22:54 · JFK 01:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.