V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
MySQL 5.5 Community Server
MySQL 5.6 Community Server
Percona Configuration Wizard
XtraBackup 搭建主从复制
Great Sites on MySQL
Percona
MySQL Performance Blog
Severalnines
推荐管理工具
Sequel Pro
phpMyAdmin
推荐书目
MySQL Cookbook
MySQL 相关项目
MariaDB
Drizzle
参考文档
http://mysql-python.sourceforge.net/MySQLdb.html
awanganddong
V2EX  ›  MySQL

mysql 并发操作的问题

  •  
  •   awanganddong · 2021-12-25 10:53:16 +08:00 · 3059 次点击
    这是一个创建于 1064 天前的主题,其中的信息可能已经有所发展或是发生改变。

    业务场景是这样的,单一用户的账号,可能会牵扯到并发问题。 就是在同一秒内,该用户的余额会频繁更新。 首先加锁这种情况不太适合。 单纯从 mysql 自身这个问题能否解决? 或者说把金额存入内存。

    这是知乎的一个提问

    https://www.zhihu.com/question/61484424

    13 条回复    2021-12-25 20:21:04 +08:00
    fkdog
        1
    fkdog  
       2021-12-25 11:44:21 +08:00   ❤️ 1
    单个用户频繁更新算不上并发。直接加行锁完事了。
    就算一秒钟更新 20 下,行锁都是绰绰有余。
    你觉得不合适大概率只是你自己觉得,跑一下压测就知道了,大多数情况只是杞人忧天。。
    0ZXYDDu796nVCFxq
        2
    0ZXYDDu796nVCFxq  
       2021-12-25 11:48:56 +08:00
    每次的变动还得计流水吧
    Saxton
        3
    Saxton  
       2021-12-25 11:57:30 +08:00
    “就是在同一秒内,该用户的余额会频繁更新。 首先加锁这种情况不太适合。”
    你这种情况就适合的就是行锁,为什么不太适合
    notejava
        4
    notejava  
       2021-12-25 12:12:00 +08:00
    乐观锁
    swcat
        5
    swcat  
       2021-12-25 12:30:32 +08:00
    加个版本,
    update xx_table set balance = :balance where id = :id and version_id = :version_id
    根据实际情况修改

    或者加个
    先锁住: select for update
    再判断: 这个也得判断下, 判断状态能否更新, 结果得大于 0 吧, 状态可以改吧....
    后更新: 更新数据

    id 为为主键
    mitu9527
        6
    mitu9527  
       2021-12-25 13:52:18 +08:00
    一般代码都是先读后写,所以除非你代码就是纯更新,否则先去开事务。
    搞清楚并发问题所竞争的资源到底是啥。到底是这条记录还是这条记录里面的金额。
    如果只是金额,看看能不能用 update ... set money = money + n 解决。
    如果上面的方式不行,可以考虑用悲观并发控制策略和乐观并发控制策略,也就是大家常说的悲观锁和乐观锁。选那种,取决于发生的频率和引发的后果到底有多大。
    悲观锁最简单的就是用 select for update 或者 redis 来实现,自己根据情况选,两种方式也都不是完美的,引入那种你认为合适的就可以了。
    乐观锁一般就是用版本号来实现。
    根据情况看看是否有必要做幂等判断,比如状态判断什么的。
    7911364440
        7
    7911364440  
       2021-12-25 14:36:11 +08:00
    把金额也作为更新条件呢?
    update t set money = money+n where id = :id and money = :money
    awanganddong
        8
    awanganddong  
    OP
       2021-12-25 15:56:33 +08:00
    业务场景就是用户之间赠送礼物,比如同一秒多个用户给一个用户 A 送礼物。
    如果这时候加行锁的话,用户这条记录就被锁定了。
    问题就在于用户这张数据表属于热表,该条记录的其他字段在其他业务也有更新操作。
    担心行锁的话,就会出现死锁的情况。

    更可怕的一点,我们这边是主从库配置,现在我暂时把代码切换成查主库,可以降低该概率的发生。
    现在对用户操作,都有日志记录。

    既然如此,现在我能发现问题,但是对于怎么成本最小的解决这个问题,或者优化这个问题,现在没有太大思路。
    awanganddong
        9
    awanganddong  
    OP
       2021-12-25 16:01:02 +08:00
    类似于客观锁这种机制,所带来问题就是用户操作的失败。
    这从代码层面其实没有太大问题,但是对于产品侧,用户体验方面,这个问题就比较严重。
    如果乐观锁校验失败,这个就更新失败。
    awanganddong
        10
    awanganddong  
    OP
       2021-12-25 16:02:10 +08:00
    我先压测下关于频繁更新的行锁情况吧。这个很靠谱的。
    sagaxu
        11
    sagaxu  
       2021-12-25 17:06:12 +08:00
    行锁每秒 10W 次是扛得住的,高配机器能做到 20W 次
    fiypig
        12
    fiypig  
       2021-12-25 19:04:46 +08:00 via iPhone
    行锁就可以,又不是表锁
    git00ll
        13
    git00ll  
       2021-12-25 20:21:04 +08:00
    for update 没问题的,每秒 4000 次
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1069 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 19:22 · PVG 03:22 · LAX 11:22 · JFK 14:22
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.