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

请教一个关于多人同时操作一条数据的问题

  •  
  •   Spider1996 · 2021-07-12 16:58:04 +08:00 · 2631 次点击
    这是一个创建于 1009 天前的主题,其中的信息可能已经有所发展或是发生改变。

    目前有个场景: 比如 A 用户选中一条数据进入设计页面,然后在 A 用户保存之前其它用户都不能操作这条数据.有什么比较好的处理 方法吗?

    29 条回复    2021-09-28 17:34:43 +08:00
    th00000
        1
    th00000  
       2021-07-12 17:03:17 +08:00
    打开 -> 加锁 => 保存 -> 释放锁
    Spider1996
        2
    Spider1996  
    OP
       2021-07-12 17:12:53 +08:00
    @th00000 这样如果用户不保存直接关闭浏览器的话 就死锁了吧... 我这业务时间不太确定 所以设置过期时间也不太行
    IvanLi127
        3
    IvanLi127  
       2021-07-12 17:25:19 +08:00
    @Spider1996 自动保存 + 锁自动过期 呢
    aitaii
        4
    aitaii  
       2021-07-12 17:27:51 +08:00
    谁先提交谁是 A 还是 指定 A 打开之后,其他人不能获取资源呢
    xiaoming1992
        5
    xiaoming1992  
       2021-07-12 17:30:20 +08:00 via Android   ❤️ 1
    心跳检测,不跳了就过期
    aitaii
        6
    aitaii  
       2021-07-12 17:30:40 +08:00
    增加一个状态字段呢,打开页面更新时更新状态为使用中,其他人再获取时状态为使用中,提交校验状态不通过
    Spider1996
        7
    Spider1996  
    OP
       2021-07-12 17:31:45 +08:00
    @aitaii 有个用户打开后 其它人就不能再操作这条记录了
    RRRSSS
        8
    RRRSSS  
       2021-07-12 17:32:47 +08:00
    Redis 分布式锁应该是最简单的

    选中数据进入页面 -> lock
    保存之后 -> unlock
    Spider1996
        9
    Spider1996  
    OP
       2021-07-12 17:34:30 +08:00
    @aitaii 这样有点太简单了..要是用户打开页面 直接关闭了浏览器 那状态就一直为使用中 其它人都操作不了了
    Spider1996
        10
    Spider1996  
    OP
       2021-07-12 17:35:09 +08:00
    @RRRSSS Redisson 吗?
    aitaii
        11
    aitaii  
       2021-07-12 17:37:44 +08:00
    @Spider1996 那看来得加个 daemon 了
    SSang
        12
    SSang  
       2021-07-12 17:38:10 +08:00
    锁要持有人去保活,做个过期时间就好了,比如 10s 过期,3s 保活一次
    meshell
        13
    meshell  
       2021-07-12 17:40:22 +08:00
    @Spider1996 如果用户直接关闭浏览器没有保存,关闭页面也有动作呀。就像上面说得也可以定时心跳。超过多少时间就释放呗 。
    chenshun00
        14
    chenshun00  
       2021-07-12 18:18:34 +08:00
    加个状态就可以了,定时心跳保活,不建议用 redis,多一个组件多一个麻烦,还用不到 redis,数据库本身就可以搞定了。这里的矛盾不在于并发有多大,粒度这么粗,数据库本身就搞定了。
    RRRSSS
        15
    RRRSSS  
       2021-07-12 18:24:02 +08:00
    @Spider1996 就从你的描述来看,用 Redission,伪代码大概是这样:

    ```java
    // 进入页面 controller:

    RLock lock = redisson.getLock("anyLock");
    // 尝试加锁 最多等待 100s 上锁以后 10s 自动解锁
    boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);

    try {
    if (res) {
    // 获取到锁
    // 业务逻辑
    }
    } catch (Exception e) {
    throw e;
    } finally {
    // 最后一定要释放锁
    if (lock != null) {
    lock.unlock();
    }
    }

    ```

    如果只是 2B 业务,可能不用那么严谨,使用 Redission 直接用 redis 就行了
    Jooooooooo
        16
    Jooooooooo  
       2021-07-12 18:36:58 +08:00
    页面的话简单, 每个人打开的页面都有版本, 后端每次更新版本都变. 写入的时候版本相等才能成功.
    dynastysea
        17
    dynastysea  
       2021-07-12 18:50:30 +08:00
    你这个需求太模糊了,至少要说清楚是单机还是多机,这两者的技术方案差的可太多了
    loveyu
        18
    loveyu  
       2021-07-12 19:12:54 +08:00
    典型的后台编辑操作(如果不是请忽略后面的内容)

    产品的需求一般是防止多人操作被覆盖(至于 A 保存之前不能操作,一般是指更新吧)

    建议找产品改需求,不是不能实现,是没必要
    akira
        19
    akira  
       2021-07-12 22:00:32 +08:00
    没有什么“好” 办法的,来去都是 加锁 保活 ,跑不掉的。

    反而是 考虑下支持多人同时修改?这个才是现在的趋势呢
    msg7086
        20
    msg7086  
       2021-07-13 00:57:12 +08:00 via Android
    还有一种做法就是允许其他人抢占锁。可以无脑参考一下 WordPress 之类软件的设计。
    xx6412223
        21
    xx6412223  
       2021-07-13 13:47:44 +08:00
    用乐观锁更合适吧
    shellus
        22
    shellus  
       2021-07-14 11:41:59 +08:00
    @chenshun00 最烦这些动不动就 redis 的。
    leohuangsulei
        23
    leohuangsulei  
       2021-07-14 13:49:42 +08:00
    @shellus 那不用 redis,用户直接关闭浏览器,这个数据,别人还要不要操作了?直接起定时任务改数据库中数据的状态吗?
    leohuangsulei
        24
    leohuangsulei  
       2021-07-14 13:51:26 +08:00
    @Spider1996 那就续期呗,js 定时发送请求,更新 redis 里面的过期时间
    saulshao
        25
    saulshao  
       2021-07-14 13:51:41 +08:00
    你这个就是给这条记录定义一个状态,然后用户 A 一旦开始编辑操作,就把这个状态更新为编辑中。
    直到用户 A 编辑完成(设一个显式的按钮)为止,其他人都只能看。没必要想那么复杂。
    管它掉线之类的,一概不理。
    liukanshan
        26
    liukanshan  
       2021-07-14 16:28:14 +08:00
    没有必要用什么分布式锁吧 在数据库加一个版本号来实现乐观锁就可以了 你说的操作这条数据应该是指修改这条数据吧 读不用加锁
    changwei
        27
    changwei  
       2021-07-14 23:28:08 +08:00
    我也很好奇,google docs 两个人同时修改同一个 excel 文件的同一个单元格会怎么样呢,有没有人研究过他们的原理
    shellus
        28
    shellus  
       2021-09-28 17:33:48 +08:00
    ```
    # 进入编辑, 成功的话这条 sql 更新记录数 1,如果被占用,就是更新记录数 0
    update posts set current_edit_uid='A', lock_time='当前时间戳' where id=123 and (current_edit_uid is null or lock_time<'当前时间-60 秒')
    # 编辑中续期,影响条数为 0 表示超时,已经被别人编辑了
    update posts set lock_time='当前时间戳' where id=123 and current_edit_uid='A'

    ```
    shellus
        29
    shellus  
       2021-09-28 17:34:43 +08:00
    @leohuangsulei 不用 redis 一样可以实现超时啊。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1364 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 23:48 · PVG 07:48 · LAX 16:48 · JFK 19:48
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.