redis缓存一致性方案,网上统一比较认同的为 延迟双删 方案。即: 写DB 删除缓存 延迟n秒 再次删除缓存 但所有文章都没有涉及到 数据库事务、 以及事务隔离性问题。 假如在一个数据库事务中,涉及到执行读写数据库操作 10 次, 那么问题是,删除缓存的时机是每次执行数据库操作之后即删除或更新缓存吗? 还是要先将事务内的数据库变动 缓存起来,等事务提交时,再一次性同步到底层redis? 在事务中更新缓存的话,带来的严重问题就是会破坏 数据库事务的隔离性,比如一般事务隔离性为读已提交,但事务中更新缓存,会导致事务隔离性变成读未提交,即事务回滚导致读到脏数据问题。 但如果缓存在整个事务结束时一次性同步redis的话, 由于事务执行时间远大于一次单独的SQL操作, 无疑会大大增加并发读写出现缓存和DB不一致的几率(即延迟双删要解决的问题)。 在实际项目中,大家都是怎么做的呢?比如要做一个查询缓存层的话 何时缓存数据、何时删除数据呢? 感谢分享!(比较奇怪,网上为何搜不到一点redis和db事务相关的内容?) ~~ 2024-07-11补充: 忽然考虑到一个比较简单的方案,初步思路如下: 目标:一个通用的DB查询缓存层,旨在提高并发环境下,相同SQL相同参数的执行性能。 原则:只和没有缓存的情况对比,能提升并发查询性能即可。所以, 1. 满足强一致性要求(这里暂不考虑redis访问失败的场景,这种情况另行处理) 2. 不考虑缓存击穿等问题,缓存原则是能缓存就缓存,可能导致缓存不一致的就丢弃; 方案: 1. 对SQL进行解析,识别查询类SQL涉及的所有TABLE; 2. 以SQL及其参数序列化作为缓存的KEY,将查询结果的二维表序列化缓存(包含列名、列类型); 3. 缓存数据以hash结构保存在redis中,除了保存二维表数据外,另外保存一个版本号信息(自增的整数); 4. 事务执行过程中,SELECT语句产生的缓存,先暂存在本地,Update/Delete语句涉及的Table也缓存在本地; 5. 事务如果回滚(显示回滚、或者连接被关闭),则丢弃本地的缓存;反之在事务提交时,将本地缓存刷新到redis中; 6. 从缓存中查询时,如果命中则直接可用;否则,记录当前缓存版本号,查询DB,事务提交时更新redis(在更新时检查版本号是否一致、同时版本号+1;如果版本号不一致,则丢弃本次更新内容) 7. 事务提交时,根据需要清理缓存的TABLE,找到所有的缓存SQL,将其value置为null,同时版本号+1; 感觉类似这种方式处理,可以比较简单实现强一致性缓存(访问redis失败的情况另行考虑)。 就是 使用版本号来实现类似乐观锁定的方式,防止DB和缓存不一致。 版本号限制了,所有的产生写缓存的操作(其相关的SQL查询)一定会发生在数据库事务提交之后、且删除缓存之后。这样延迟双删要解决的不一致场景就不存在了。 另外,hibernate的二级缓存是保证集群之间的缓存一致性呢?是否存在同样的问题呢?有时间再看一下!
一个发布项目用的接口,需要做这些操作: 1. 检查此项目的状态,是否可以发布(只有未发布过的才可以发布) 2. 后端上传文件(可能有很多个文件,现在一个请求是最多 10 并发上传)到云服务(对象存储),文件不在前端,在后端,发布之前不允许提前将这些文件传到云对象存储 3. 文件全都上传成功后,改写此项目状态为已发布 4. 返回结果,前端结束 loading 状态,提示发布成功 请问这个接口应该怎么设计?因为整体比较耗时,有可能在中间上传文件的过程中失败。 我先谈下我的理解: 1. 检查项目状态的时候,就加上悲观锁,不允许其他请求读取此项目的状态 2. 上传的过程中,如果有失败,就返回失败信息,结束此请求 3. 都成功的话,就改写项目状态后,解锁,其他请求可以继续
Java类上加事务注解(@transactional),会导致该类中所有方法都开启事务吗 如何分析类上加注解,类中每一个方法是否开启事务
https://wmprod.oss-cn-shanghai.aliyuncs.com/c/user/20240914/199c49b847f3889f26c86c9c76857af8.png