由于前端需要用户信息userInfo,后端各个模块,例如报表也需要用户信息,查询的频率很高,涉及到较多的联表。
而实际系统用户较小,数据基本不变,为各模块方便查询,决定采取缓存。
选择将其放到Redis数据库中,访问用户数据时,模块间得到解耦。
1. 函数
userInfo的部分字段可能来自于函数。
由于需要,在我拿到一个用户的时候,我同时需要得知他是属于哪个顶级组织的。
组织表如下:
orgId | orgName | parentOrgId |
---|---|---|
1 | 老板 | null |
2 | 组织一 | 1 |
3 | 组织二 | 1 |
首先,创建一个函数,根据orgId
获取rootId
CREATE FUNCTION `queryRoot`(org varchar(32))
RETURNS varchar(32)
BEGIN
# 定义子节点、父节点
DECLARE nodeId VARCHAR(32);
DECLARE parentId VARCHAR(32);
DECLARE rootId VARCHAR(32);
# 赋值
SET nodeId = org;
SET parentId = '$';
WHILE parentId IS NOT NULL DO
SELECT parentOrgId INTO parentId FROM T_ORG WHERE ORG_ID = nodeId;
SET rootId = nodeId;
SET nodeId = parentId;
END WHILE;
RETURN rootId;
END;
2. 视图
SELECT
`users`.`USER_ID` AS `userId`,
`users`.`ORG_ID` AS `orgId`,
(
SELECT
`queryRootByOrgId` (`users`.`ORG_ID`)
) AS `rootOrgId`,
`orgs`.`ORG_NAME` AS `orgName`,
`users`.`USER_NAME` AS `userName`
FROM
(
`T_USERS` `users`
JOIN `T_ORG` `orgs` ON (
(
`users`.`ORG_ID` = `orgs`.`ORG_ID`
)
)
)
3. 定时更新到Redis
其中用到了反射,将属性及值存到Hash里面。
@EnableScheduling
@Component
public class RedisTask {
@Autowired
private StringRedisTemplate redis;
@Autowired
private UserInfoRepository userInfoRepository;
static Field[] fields;
static {
fields = UserInfo.class.getDeclaredFields();
for (Field field : fields)
field.setAccessible(true);
}
/**
* 定时 3min 查询数据库,然后更新到 redis 中
*/
@Scheduled(fixedRate = 3*60*1000)
private void userInfo() {
List<UserInfo> list = userInfoRepository.findAll();
list.forEach(user -> {
Map<String, String> map = new HashMap();
String hashKey, hashValue, hash = user.getUserId();
for (Field field : fields) {
try {
hashKey = field.getName();
if (field.get(user) != null)
hashValue = field.get(user).toString();
else
hashValue = "";
map.put(hashKey, hashValue);
} catch (Exception e) {
System.out.println("反射异常");
e.printStackTrace();
}
}
redis.opsForHash().putAll(hash, map);
});
}
}