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

postgresql 里面的事务,明明又错误为什么也执行了?

  •  
  •   Fixedsys · 2022-09-26 03:41:42 +08:00 · 2400 次点击
    这是一个创建于 788 天前的主题,其中的信息可能已经有所发展或是发生改变。

    本人在初学 postgresql ,版本 14 ,关于事务,教程里说的额是如果有一个错误所有的命令都不会执行。

    但是下面的这个例子里面,原始表里并没有“T 恤衫”这个产品名,而是“T 恤”,所以将“T 恤衫”的价格上浮 1000 日元这个指令筛选不出来“T 恤衫”,我理解应该是错误的,但是 commit 之后,只有“运动 T 恤”的价格下调了,“T 恤衫”上浮 1000 并没有实现。

    这个怎么解释呢?

    shop=# select * from product;
     product_id | product_name | product_type | sale_price | purchase_price | regist_date
    ------------+--------------+--------------+------------+----------------+-------------
     0001       | T 恤          | 衣服         |       1000 |            500 | 2009-09-20
     0002       | 打孔器       | 办公用品     |        500 |            320 | 2009-09-11
     0003       | 运动 T 恤      | 衣服         |       4000 |           2800 |
     0004       | 菜刀         | 厨房用具     |       3000 |           2800 | 2009-09-20
     0005       | 高压锅       | 厨房用具     |       6800 |           5000 | 2009-01-15
     0006       | 叉子         | 厨房用具     |        500 |                | 2009-09-20
     0007       | 擦菜板       | 厨房用具     |        880 |            790 | 2008-04-28
     0008       | 圆珠笔       | 办公用品     |        100 |                | 2009-11-11
    (8 行记录)
    
    
    shop=# BEGIN TRANSACTION;
    BEGIN
    shop=*# -- 将运动 T 恤的销售单价降低 1000 日元
    shop=*# UPDATE Product SET sale_price = sale_price - 1000 WHERE product_name = '运动 T 恤';
    UPDATE 1
    shop=*# -- 将 T 恤衫的销售单价上浮 1000 日元
    shop=*# UPDATE Product SET sale_price = sale_price + 1000 WHERE product_name = 'T 恤衫';
    UPDATE 0
    shop=*# COMMIT;
    COMMIT
    shop=# select * from product;
     product_id | product_name | product_type | sale_price | purchase_price | regist_date
    ------------+--------------+--------------+------------+----------------+-------------
     0001       | T 恤          | 衣服         |       1000 |            500 | 2009-09-20
     0002       | 打孔器       | 办公用品     |        500 |            320 | 2009-09-11
     0004       | 菜刀         | 厨房用具     |       3000 |           2800 | 2009-09-20
     0005       | 高压锅       | 厨房用具     |       6800 |           5000 | 2009-01-15
     0006       | 叉子         | 厨房用具     |        500 |                | 2009-09-20
     0007       | 擦菜板       | 厨房用具     |        880 |            790 | 2008-04-28
     0008       | 圆珠笔       | 办公用品     |        100 |                | 2009-11-11
     0003       | 运动 T 恤      | 衣服         |       3000 |           2800 |
    (8 行记录)
    
    7 条回复    2022-09-26 19:38:36 +08:00
    dayeye2006199
        1
    dayeye2006199  
       2022-09-26 04:11:33 +08:00 via Android   ❤️ 2
    没毛病,两条语句都执行成功了,所以事物成功了。第一条更新 1 条记录,第二条更新 0 条记录,都执行成功。
    你问的应该是,怎么让更新 0 条记录的时候 update 语句失败,而不是成功。你可以在 update 之后加 returning id ,返回受到更新影响的行的主键。这时候 0 条记录更新的情况下,会直接失败。
    moen
        2
    moen  
       2022-09-26 04:16:57 +08:00   ❤️ 1
    呃,你这个查询是顺利执行,只不过是无法匹配记录导致更新 0 行记录。没有顺利执行的那才是导致事务出错回滚
    felixcode
        3
    felixcode  
       2022-09-26 05:23:06 +08:00 via Android   ❤️ 3
    SQL 是描述型语言,描述和操作的都是集合。
    所以匹配不上就是空集,而不是运行报错。
    PendingOni
        4
    PendingOni  
       2022-09-26 07:58:41 +08:00
    @dayeye2006199 #1 正解,只要 SQL 事务操作中没有抛出异常就会一直执行,T 恤衫没有影响到任何一行
    nekoneko
        5
    nekoneko  
       2022-09-26 17:40:04 +08:00
    你数据库哪有 'T 恤衫' 这个 product_name 啊
    nekoneko
        6
    nekoneko  
       2022-09-26 17:41:09 +08:00
    # 1 正解
    Fixedsys
        7
    Fixedsys  
    OP
       2022-09-26 19:38:36 +08:00
    好的,明白了,感谢各位大佬。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1208 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 23:19 · PVG 07:19 · LAX 15:19 · JFK 18:19
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.