但是访问数据库查询将消耗一些时间,此时另一个请求进来也发现该对象不在缓存中,又访问一次数据库查询。
在更新缓存时也存在同样的问题。在更新尚未完成时,那些请求怎么办?
请问这种并发问题大家是怎么解决的?
9 个解决方案
#1
读数据的前同步,读完,放入缓存后解锁
#2
漏了很重要的一点
// 判断是否有缓存
if (cached) {
// 直接返回缓存内容
return cachedValue;
}
// 开始同步
synchronized (lock) {
// 这点刚才漏了
// 再次判断,避免在等待同步锁的过程中,别人已经先行一步读取了DB
if (isThisTimeCached) {
return cached;
}
// 读取DB
readDB();
// 存入cache
saveCache();
return cached;
}
// 判断是否有缓存
if (cached) {
// 直接返回缓存内容
return cachedValue;
}
// 开始同步
synchronized (lock) {
// 这点刚才漏了
// 再次判断,避免在等待同步锁的过程中,别人已经先行一步读取了DB
if (isThisTimeCached) {
return cached;
}
// 读取DB
readDB();
// 存入cache
saveCache();
return cached;
}
#3
至于同步机制,看情况或个人喜好。重要的是,进入同步代码之后,二次判断
#4
太感谢了,shine333讲的太清楚了,我正想问第二个问题呢,原来是用二次判断,否则光同步还不行呢
另外请教,采用同步方式时,如果同步块中更新缓存的过程很长,会降低性能的,有何思路可以避免这个问题呢?是否只能在设计缓存对象上注意避免时间过长的更新?
另外请教,采用同步方式时,如果同步块中更新缓存的过程很长,会降低性能的,有何思路可以避免这个问题呢?是否只能在设计缓存对象上注意避免时间过长的更新?
#5
详细解释一下“更新缓存的过程很长”是
同步块内连同DB操作的时间很长?
还是单单更新cache中element的时间很长?
后者好像不太可能啊,除非用了cluster之类的。
同步块内连同DB操作的时间很长?
还是单单更新cache中element的时间很长?
后者好像不太可能啊,除非用了cluster之类的。
#6
同步块内连同DB操作的时间很长了,我是把权限对应放到缓存中,需要几个表的关联查询,对权限的任何修改都更新整个Cache
#7
cache中存放角色与功能号的对应,用于判断是否有权限,key形如:"roleID_functionId",当角色的权限被修改或某个功能号被删除等情况下,重建这个cache。
局部更新cache代价同样太高了,遍历所有前缀为某角色的键的缓存,或者遍历所有后缀为某功能号的键的缓存,这种方式代价太高了;
而按角色名放在不同的Cache中,当角色的权限更改时仅更新这一个cache,但又无法适应功能号的修改的情况。
局部更新cache代价同样太高了,遍历所有前缀为某角色的键的缓存,或者遍历所有后缀为某功能号的键的缓存,这种方式代价太高了;
而按角色名放在不同的Cache中,当角色的权限更改时仅更新这一个cache,但又无法适应功能号的修改的情况。
#8
是不是整个功能用来判断用户是否可以操作某个功能?
个人感觉存放形式应当改一下
cache.key roleId
cache.value ROLE对象或者Map, Map的key是 functionId
这样只要更新一个对象。
功能号被删除这个情况,我想在实际环境中出现的可能性比较小,这个时候,应该需要重新发布,重启之类,cache都失效,无需担心。
个人感觉存放形式应当改一下
cache.key roleId
cache.value ROLE对象或者Map, Map的key是 functionId
这样只要更新一个对象。
功能号被删除这个情况,我想在实际环境中出现的可能性比较小,这个时候,应该需要重新发布,重启之类,cache都失效,无需担心。
#9
想看看回复 ,急需解决这个问题
#1
读数据的前同步,读完,放入缓存后解锁
#2
漏了很重要的一点
// 判断是否有缓存
if (cached) {
// 直接返回缓存内容
return cachedValue;
}
// 开始同步
synchronized (lock) {
// 这点刚才漏了
// 再次判断,避免在等待同步锁的过程中,别人已经先行一步读取了DB
if (isThisTimeCached) {
return cached;
}
// 读取DB
readDB();
// 存入cache
saveCache();
return cached;
}
// 判断是否有缓存
if (cached) {
// 直接返回缓存内容
return cachedValue;
}
// 开始同步
synchronized (lock) {
// 这点刚才漏了
// 再次判断,避免在等待同步锁的过程中,别人已经先行一步读取了DB
if (isThisTimeCached) {
return cached;
}
// 读取DB
readDB();
// 存入cache
saveCache();
return cached;
}
#3
至于同步机制,看情况或个人喜好。重要的是,进入同步代码之后,二次判断
#4
太感谢了,shine333讲的太清楚了,我正想问第二个问题呢,原来是用二次判断,否则光同步还不行呢
另外请教,采用同步方式时,如果同步块中更新缓存的过程很长,会降低性能的,有何思路可以避免这个问题呢?是否只能在设计缓存对象上注意避免时间过长的更新?
另外请教,采用同步方式时,如果同步块中更新缓存的过程很长,会降低性能的,有何思路可以避免这个问题呢?是否只能在设计缓存对象上注意避免时间过长的更新?
#5
详细解释一下“更新缓存的过程很长”是
同步块内连同DB操作的时间很长?
还是单单更新cache中element的时间很长?
后者好像不太可能啊,除非用了cluster之类的。
同步块内连同DB操作的时间很长?
还是单单更新cache中element的时间很长?
后者好像不太可能啊,除非用了cluster之类的。
#6
同步块内连同DB操作的时间很长了,我是把权限对应放到缓存中,需要几个表的关联查询,对权限的任何修改都更新整个Cache
#7
cache中存放角色与功能号的对应,用于判断是否有权限,key形如:"roleID_functionId",当角色的权限被修改或某个功能号被删除等情况下,重建这个cache。
局部更新cache代价同样太高了,遍历所有前缀为某角色的键的缓存,或者遍历所有后缀为某功能号的键的缓存,这种方式代价太高了;
而按角色名放在不同的Cache中,当角色的权限更改时仅更新这一个cache,但又无法适应功能号的修改的情况。
局部更新cache代价同样太高了,遍历所有前缀为某角色的键的缓存,或者遍历所有后缀为某功能号的键的缓存,这种方式代价太高了;
而按角色名放在不同的Cache中,当角色的权限更改时仅更新这一个cache,但又无法适应功能号的修改的情况。
#8
是不是整个功能用来判断用户是否可以操作某个功能?
个人感觉存放形式应当改一下
cache.key roleId
cache.value ROLE对象或者Map, Map的key是 functionId
这样只要更新一个对象。
功能号被删除这个情况,我想在实际环境中出现的可能性比较小,这个时候,应该需要重新发布,重启之类,cache都失效,无需担心。
个人感觉存放形式应当改一下
cache.key roleId
cache.value ROLE对象或者Map, Map的key是 functionId
这样只要更新一个对象。
功能号被删除这个情况,我想在实际环境中出现的可能性比较小,这个时候,应该需要重新发布,重启之类,cache都失效,无需担心。
#9
想看看回复 ,急需解决这个问题