文章内容

2026/1/21 20:07:51,作 者: 黄兵

一条经典 SQL 查询语句

这是一条 SQL 查询语句:

INSERT INTO cloud_product_account_balance (user_id, balance, time_updated, create_time)
VALUES (%s, %s, UTC_TIMESTAMP(), UTC_TIMESTAMP())
ON DUPLICATE KEY UPDATE
balance = balance + VALUES(balance),
time_updated = UTC_TIMESTAMP() 

这条 SQL 语句非常经典且高效,通常被称为 "Upsert"Update + Insert)。

它的核心作用是:“如果记录不存在就插入,如果记录存在就更新”,而且这一切是在一条 SQL 语句中原子完成的。

让我们拆解一下这条语句的逻辑:

1. 核心逻辑拆解

这条语句分为三部分来看:

第一部分:尝试插入
INSERT INTO cloud_product_account_balance (user_id, balance, ...)
VALUES (%s, %s, ...)
  • 动作:首先,数据库尝试把它当做一个普通的插入操作。

  • 假设:我们要插入 user_id=101, balance=50.00

第二部分:捕获冲突
ON DUPLICATE KEY
  • 触发条件:在你的 cloud_product_account_balance 表模型中,user_id 字段被定义为 unique=True(唯一索引)。

  • 逻辑

    • 如果数据库里没有 user_id=101 的记录,第一部分的插入就成功了,流程结束。

    • 如果数据库里已经有 user_id=101 的记录,插入会失败(报 Duplicate entry 错误)。此时,数据库不会报错,而是触发后面的 UPDATE 操作。

第三部分:执行更新
UPDATE 
    balance = balance + VALUES(balance),
    time_updated = UTC_TIMESTAMP()

这是最精彩的地方,只有在发生冲突(即用户已存在)时才会执行:

  • balance (等号右边):指数据库里现有的余额(比如用户之前有 100 元)。

  • VALUES(balance):指你刚才试图插入、但没插进去的那个值(本次退款的 50 元)。

  • 结果新余额 = 旧余额(100) + 本次退款(50) = 150 元。

2. 举个生动的例子

假设我们要给用户 ID: 888 退款 $10

场景 A:这是一个新用户(或者他以前从来没有余额记录)

  1. 执行: 试图插入 (user_id=888, balance=10)

  2. 检查: 表里没有 888。

  3. 结果: 插入成功。现在表里有一行:{user_id: 888, balance: 10}

场景 B:这是一个老用户(表里已经有他的记录,余额 $200)

  1. 执行: 试图插入 (user_id=888, balance=10)

  2. 检查: 表里已经有 888 了!触发 ON DUPLICATE KEY UPDATE

  3. 计算:

    • balance (旧值) = 200

    • VALUES(balance) (新来的值) = 10

    • balance = 200 + 10

  4. 结果: 更新成功。现在表里的记录变成:{user_id: 888, balance: 210}

3. 为什么要在这里用它?

在你的代码中,使用这个写法有三个巨大的好处:

  1. 代码简洁 (Simplicity)

    • 不用写:SELECT 查一下有没有人 -> if 有人则 UPDATE -> else 没人则 INSERT

    • 一行 SQL 搞定所有情况。

  2. 并发安全 (Concurrency Safety)

    • 如果是“先查后写”的两步操作,在高并发下可能会出 Bug(比如两个线程同时查到“没记录”,然后都试图插入,导致其中一个报错)。

    • 这条 SQL 是原子性的,MySQL 会自动加锁,保证资金计算绝对安全。

  3. 数据完整性 (Robustness)

    • 它完美处理了“用户第一次产生退款”这种边界情况,不需要你手动去初始化用户的余额表。

总结

这句话的意思是:“给这个用户存入这笔钱。如果他是新用户,就直接建档存入;如果他是老用户,就在他原有余额的基础上加上这笔钱。”


其它相关推荐:

1、MySQL 检查表有哪些外键约束

2、MySQL查询表中重复字段和重复的次数

3、MySQL 查询排序

4、MySQL 插入 Emoji 表情符号出现错误

5、商品收藏相关问题

AI 给我挖的一个坑
没有了
分享到:

发表评论

评论列表