开发者学堂课程【高校精品课-厦门大学 -JavaEE 平台技术:用户和角色的缓存】学习笔记,与课程紧密联系,让用户快速学习知识
课程地址:https://developer.aliyun.com/learning/course/80/detail/15975
用户和角色的缓存
在 road 部分来说,其功能非常简单,即把一个 road 的权限搂到 dedis 中间。这个方法的做法是用自动生成代码到数据库里去查,中间三段是用数据库生成的代码,其生成了example 可以用来去组一个条件,这部分应该一看就知道,是用 role id 组了一个条件,然后到数据库里去查出来以后,使用一个循环。
现在用的不是 bit map,而是一个 sit,所以循环里头所做的事情,就是往 sit 里头不停的去 add,其中代码最下面的 key 和上方是同一个 key。因为它是个 sit,所以每次对同一个 key 去做 add 操作时,就是把它加进去,它有可能是已经有了,若已经有了就加不进去,不用去管它,没有的话,sit 就会加入一个新的权限 id 里面。这样针对一个角色来说,它的 R_ID 在 redis 中间就会有一个 sit,这个 sit 是它所有 privilege 的 ID,这部分是 loadrolepriv,把 road 的权限 low 到缓存里头。
/**
*
将一个角色的所有权限 id 载入到Redis
*@eparam id
角色 id
*/
public void loadRolePriv(Long id){
String key ="r"+ id;
RolePrivilegePoExampleexample=newRolePrivilegePoExample();
RolePrivilegePoExample.Criteriacriteria=example.createCriteria();criteria.andRoleIdEqualTo(id);
List<RolePrivilegePo>rolePrivilegePos=rolePrivilegePoMapper.selectByExample(example)
for (RolePrivilegePo po:rolePrivilegePos){
redisTemplate.opsForSet().add(key,po.getId).toString());
}
}
}
接下来看一下 user,其里面分了两块,一块是 low 自己的权限,一块是去 low 代理的权限和自己的权限合起来。
首先看 low 自己的权限,其实很简单,就是每一个用户自己的权限是 u 下划线开头
加上 ID 在 redis 中间去存,前面是根据用户去查角色,查到角色以后,把所有的角色 low 上来。
这一段 roleDao.loadRolePriv(po.getRoleId()) 首先在缓存中间去找一下这个角色有没有 low 过,如果没有,就把这个角色 low上来,然后会把 Key 加到rolekey 里。有一个非常好用的方法,将所有角色的 Key 合起来,求并集,然后把它存到后面
Key 上去。
这样其实就完成了把用户所有角色的权限,并求一个合集,存成这个用户当前的权限。这里一句话就搞定了,而且这句话还是原子操作,前面提到了,redis 是一个原子操作,所以这句话是原子操作,将它一次搞定。如果有多个人同时来做这件事情的时候,也是分先后的,不会插进去,因为这句运行起来还挺复杂的,但是该原子操作它就是隔离的,而且做完别人的,才可以做,互斥的原次操作。对于代理的部分,可以看到做法是前面让其去查它的代理,这样就有两个用户了,代理是直接
代理,不能做代理的传递,不能 a 代理b,b 代理 c,然后得出 a 就有 c 的权限,这样就永远没完了。
正确为 a 代理 b,那 a 只有 b 权限,b 代理 c,b 只有 b 和 c 的权限,不做代理的传递。所以 a 可以查自己代理了哪些用户,每个用户把 road 的权限给 low 起来,然后将所有它的权限,(key,proxyUserKey,aKey)这是权限制,是它所有代理用户的权限制。因为这是一个 list,所以其可能会代理很多个人,将 key 和 proxyUserKey 求交集存到 aKey 上去,这是最后的结果,存到上面去。同样是个很复杂的操作,但是 redis 的集合操作提供了一个原则性的方法,能将 key 和 proxyUserKey 求并集,最后存到 aKey 上去,aKey 就是最后要的结果。即在 redis 中间存在叫做 up 开头的 ID,就是用户和它的代理加起来权限的集合存进去,之后直接用up_+ID 到
里面去拿即可。
如果 up_+ID 拿不到,调 loadUserPriv(Long id) 方法去将权限 low起来,就可以知
道该用户有什么样的权限了。
所以这一段代码,展示出的,讲解的,主要的地方在于,redis 的引入对写代码是
一个革命性的变化。
之前在写代码的时候,可能更多的想在数据库里去拿、数据库里去做处理,然后得出一个结果,但是会发现 redis 是一个非常强大的东西,它不仅仅是用来做缓存的东西,最关键的是它在缓存上面是有多种数据操作的。特别是可以看到它集合操作的强大现象,而且它是原子操作,所以利用 redis 集合的操作,可以把很多的功能依赖于 redis 去完成。
这样代码的出现其实就变得很简单,代码只是在数据库里去做查询,利用 redis 的
功能去完成想要的东西,所以 redis 的引入其实会改变写程序的一种生态和写法。不要简单的认为它只是一个缓存,其实能存数据结构的话,可以做很多的东西。
public void loadUserPriv(Long id){
String key = "u_"+id;
String aKey ="up_"+id;
UserProxyPoExample example=newUserProxyPoExample();
UserProxyPoExample.Criteriacriteria=examplecreateCriteria(); criteria.andUserAIdEqualTo(id);
List<UserProxyPo>userProxyPos=userProxyPoMapperselectByExample(example)
List<string>proxyUserKey=new ArrayList<>(userProxyPos.size());
for (UserProxyPo po:userProxyPos){
if(lredisTemplate.hasKey("u_"+po.getUserBId())){
loadUserPriv(po.getUserBid());
}
proxyUserKey.add(“u_“+po.getUserBId());
}
if(lredisTemplate,hasKey(key)){
loadUserPriv(id);
}
redisTemplate.opsForSet().unionAndStore(key, proxyUserkey,aKey);
}
}