关于spring缓存的问题: "c1cfcce2dfe27824305d245b228613c.png" (https://wmprod.oss-cn-shanghai.aliyuncs.com/c/user/20241014/6a6352e88557eaee0aacb4648523d77e.png) "e0d7898d75f80be3e2ff5ccc5fa86de.png" (https://wmprod.oss-cn-shanghai.aliyuncs.com/c/user/20241014/67376c3488d5d6be3b2eba456f36951e.png) 1. 类似我通过注解方式定义的缓存,我定义了设置缓存,获取缓存、删除缓存三个方法,但我感觉其中设置、删除缓存方法都很奇怪,设置缓存居然要提供返回值才能实际设置;删除缓存又是一个空的方法体。缓存是通过这种方式使用的吗?我感觉很奇怪 2. 我在 application.yml 中配置了缓存的 cache-names;然后使用 @Cachable 注解IDE还是会提示要提供 name,有办法取消这种警告吗 3. 上面获取缓存的值的方法我感觉有点复杂;先获取cache;在获取值的包装类,在获取值,而且每一步都要检查是否为null好麻烦,有更简便的做法吗 无
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. 我知道java volatile可以保证可见性和有序性。 2. 我知道java单例实现:double-check模式需要加上volatile, 但是为什么需要加上volatile?百度好像有两种意见。 基于可见性 的考虑,参考:"https://www.bilibili.com/video/BV1gX4y1a7sH?p=11&vd_source=80..." (https://www.bilibili.com/video/BV1gX4y1a7sH?p=11&vd_source=801503831f64778f7f89c8223c80acac) 作者的意思:没有加上volatile,不同的线程间的缓存副本无法可见,导致重复多次初始化。 基于有序性 的考虑,参考:"https://blog.csdn.net/qq_44842835/article/details/132166785" (https://link.segmentfault.com/?enc=SdiGpHN2ojNGS8Oa9U7fYQ%3D%3D.AuPlZZ%2FhXC2zfEwzN6xuTUWkJWNs%2FPY2HdjAjBgUm%2FB4JgipF0ibnfPpt0CIbrtA6BGZMUuEZKlSKRJQs3Bnhg%3D%3D) 作者的意思:对象实例化可以简单分为三步:1、分配内存 2、初始化对象 3、将对象的引用赋值给instance。因为指令重排,顺序可以变成1->3->2,因此其他线程很可能获得一个未完全初始化的实例。 请问上述两种观点谁对谁错?能否能通过java代码来证明和实现?
比如现在redis有3个集群分片(A、B、C), 有一个高频热点key,保存在分片A上,会导致请求的倾斜,使得A分片的读取压力过大。 现在希望将key设计成:key1、key2、key3,都对应相同的value 存储的时候: key1存在分片A key2存在分片B key3存在分片C 查询的时候: key随机转化成key1、key2、key3的其中一个,然后路由到某个分片上。 key1、key2、key3的值改怎么设计? 开发人员怎么知道一个key对应的哈希值是多少
使用缓存实现一个功能,存储当前时间前24小时的抽奖奖励记录,有以下要求: 1. 奖励记录条数5条; 2. 每条记录最长过期时间24h; 3. 若有新的满足条件的奖励记录,且记录条数小于5条,则删除最早的奖励记录,插入该条奖励记录。 4. 奖励记录需要一次性查出来; 大佬们有什么比较好的解决思路吗?或者又遇到这类问题么? 我的思路: 把所有抽奖记录ID存储在一个set或者list中,这样可以一次性获取到所有的抽奖记录。 每条抽奖记录作为一个独立的键值对存储在redis中,并设置对应的过期时间。这种设计在插入数据比较麻烦。 请问这类问题是否存在现有解决方案?
React中组件A里有个获取配置数据的异步请求,列表中多个组件A就会触发多个相同的异步请求,期望是等到第一个异步请求回来进行数据缓存,剩下组件直接读取缓存来获取配置数据。 我想了一下,使用axios的拦截器把请求拦截下来处理,但是如何让剩下的组件进行等待呢?或者有什么其他思路?