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

在 Redis 中怎么实现代码出现异常时数据回滚

  •  
  •   suyuanhxx ·
    suyuanhxx · 2016-12-01 10:47:23 +08:00 · 7447 次点击
    这是一个创建于 2913 天前的主题,其中的信息可能已经有所发展或是发生改变。

    场景:一段代码中有两处数据库操作(保存和更新,先保存后更新,两张表),保存数据库同时将数据保存到缓存,更新数据库时同时更新缓存。当更新数据库代码出现异常时,数据库可以使用事务的方式实现回滚,如果这时已经保存到缓存的数据怎么回滚?

    当然可以在异常捕获中删除缓存,这样子有点粗暴...

    如果是先更新后保存,缓存是不是回不去了?示意图我就不贴了,相信 V 站大神都能看懂

    第 1 条附言  ·  2016-12-01 13:42:05 +08:00
    根据 @virusdefender 这位给出的资料,我已经有了思路,淘汰缓存-》先淘汰缓存,再写数据库,这样不容易出错(也能尽可能避免脏数据),但会增加缓存 miss 次数
    第 2 条附言  ·  2016-12-01 19:59:27 +08:00
    附言中说的不是很对,好像要根据不同的场景,使用不同的缓存淘汰策略
    22 条回复    2018-11-13 16:08:30 +08:00
    suyuanhxx
        1
    suyuanhxx  
    OP
       2016-12-01 11:07:22 +08:00
    是不是节点选错了...
    server
        2
    server  
       2016-12-01 11:11:52 +08:00
    为啥已经要把缓存放到事务里
    lrh3321
        4
    lrh3321  
       2016-12-01 11:21:31 +08:00
    不是应该 更新 /保存 成功以后,再去更新缓存的吗?
    est
        5
    est  
       2016-12-01 11:36:30 +08:00   ❤️ 1
    coolshell 缓存更新的套路

    http://coolshell.cn/articles/17416.html
    suyuanhxx
        6
    suyuanhxx  
    OP
       2016-12-01 12:49:24 +08:00
    @server
    @lrh3321 公司代码习惯, service 层保存数据库时立马保存到缓存,防止忘记数据缓存
    suyuanhxx
        7
    suyuanhxx  
    OP
       2016-12-01 12:50:04 +08:00
    @est
    @virusdefender 3Q ,我去看看
    moro
        8
    moro  
       2016-12-01 13:05:57 +08:00
    redis 事务这章你看看能不能满足你的要求。
    https://redis.io/topics/transactions
    jyf
        9
    jyf  
       2016-12-01 13:18:18 +08:00
    mvvm
    suyuanhxx
        10
    suyuanhxx  
    OP
       2016-12-01 13:39:16 +08:00
    @moro redis 事务我们有用,但不是这个场景,并发更新缓存时使用。这个场景是读写数据库和缓存的问题
    Mirana
        11
    Mirana  
       2016-12-01 13:58:07 +08:00
    先更新数据库 在更新缓存,要不会有并发一致性的问题
    suyuanhxx
        12
    suyuanhxx  
    OP
       2016-12-01 13:59:52 +08:00
    @Mirana 你说的是应该是异步执行, pub sub 的模式?
    Mirana
        13
    Mirana  
       2016-12-01 14:24:02 +08:00
    @suyuanhxx 不是啊 业务里实现就可以,写不去更新缓存,写成功让缓存失效,读 miss 之后去数据库拉然后回种
    moro
        14
    moro  
       2016-12-01 14:36:35 +08:00
    先淘汰缓存,不能避免同时被读旧数据而载入缓存,还是会有脏数据。
    MrJing1992
        15
    MrJing1992  
       2016-12-01 15:01:18 +08:00
    先淘汰缓存也有问题的。
    suyuanhxx
        16
    suyuanhxx  
    OP
       2016-12-01 19:52:54 +08:00
    @Mirana 按照你的思路,写成功-》淘汰缓存-》如果更新失败-》数据库回滚,(如果更新成功也是一样)缓存一定 miss ,拉取数据库数据到缓存。那我们就要重新设计缓存思路,也就是只在读时将数据存到缓存,而且数据第一次被都读时缓存一定 miss 。或者将这一次存储时只存数据库。这样写代码不够优雅....(此处鬼脸)。如果先先更新,后保存就不适用了.....
    suyuanhxx
        17
    suyuanhxx  
    OP
       2016-12-01 19:58:40 +08:00
    @moro 高并发时会有脏数据产生,在淘汰掉缓存后和更新时第二张表时此时发生读操作,就会产生脏数据。可以使用 redis 中的事务 watch key 防止此时的都操作产生的脏数据。
    Mirana
        18
    Mirana  
       2016-12-01 23:41:09 +08:00
    @suyuanhxx 写成功,为什么会更新失败呢。 我说的写成功是指数据库事务都提交了才算。。
    suyuanhxx
        19
    suyuanhxx  
    OP
       2016-12-02 09:39:51 +08:00
    @Mirana 场景里面提到了,保存是一张表,更新是一张表,两张表都可能出错
    suyuanhxx
        20
    suyuanhxx  
    OP
       2016-12-02 09:44:04 +08:00
    @Mirana 如果保存和更新同时使用事务包裹,在这个事务执行时高并发情况下读的还是脏数据。而且我这个还是对整个 list 进行遍历读写....
    Mirana
        21
    Mirana  
       2016-12-02 17:55:53 +08:00
    @suyuanhxx 事务开始前淘汰缓存 然后执行事务 提交事务 这样不会有脏数据 但是要注意事务的隔离级别
    HansCathy
        22
    HansCathy  
       2018-11-13 16:08:30 +08:00
    两张表直接放两个事务啊,单事务会有问题
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5435 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 06:42 · PVG 14:42 · LAX 22:42 · JFK 01:42
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.