因爲前端須要用戶信息userInfo,後端各個模塊,例如報表也須要用戶信息,查詢的頻率很高,涉及到較多的聯表。前端
而實際系統用戶較小,數據基本不變,爲各模塊方便查詢,決定採起緩存。java
選擇將其放到Redis數據庫中,訪問用戶數據時,模塊間獲得解耦。node
userInfo的部分字段可能來自於函數。redis
因爲須要,在我拿到一個用戶的時候,我同時須要得知他是屬於哪一個頂級組織的。sql
組織表以下:數據庫
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;
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` ) ) )
其中用到了反射,將屬性及值存到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); }); } }