企業專案開發--本地快取guava cache(2)
此文已由作者趙計剛授權網易雲社群釋出。
歡迎訪問網易雲社群,瞭解更多網易技術產品運營經驗。
AdminCacheKey:
package com.xxx.vo.userManagement; /** * guava cache的key */ public class AdminCacheKey { private String username; private String password; private int start; private int limit; public AdminCacheKey() { } public AdminCacheKey(String username, String password, int start, int limit) { this.username = username; this.password = password; this.start = start; this.limit = limit; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public int getStart() { return start; } public void setStart(int start) { this.start = start; } public int getLimit() { return limit; } public void setLimit(int limit) { this.limit = limit; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + limit; result = prime * result + ((password == null) ? 0 : password.hashCode()); result = prime * result + start; result = prime * result + ((username == null) ? 0 : username.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; AdminCacheKey other = (AdminCacheKey) obj; if (limit != other.limit) return false; if (password == null) { if (other.password != null) return false; } else if (!password.equals(other.password)) return false; if (start != other.start) return false; if (username == null) { if (other.username != null) return false; } else if (!username.equals(other.username)) return false; return true; } }
該類是封裝了多個查詢條件的一個VO類。
2.2、ssmm0-userManagement
AdminController:
package com.xxx.web.admin; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import com.xxx.model.userManagement.Admin; import com.xxx.service.userManagement.AdminService; import com.xxx.util.admin.AdminCookieUtil; /** * adminController */ @Controller @RequestMapping("/admin") public class AdminController { @Autowired private AdminService adminService; /** * 管理員註冊 */ @ResponseBody @RequestMapping("/register") public boolean register(@RequestParam("username") String username, @RequestParam("password") String password){ Admin admin = new Admin(); admin.setUsername(username); admin.setPassword(password); boolean isRegisterSuccess = adminService.register(admin); return isRegisterSuccess; } /** * 管理員登入 */ @RequestMapping("/login") public ModelAndView login(@RequestParam("username") String username, @RequestParam("password") String password, HttpServletResponse response, HttpSession session){ Admin admin = adminService.login(username, password); ModelAndView modelAndView = new ModelAndView(); if(admin == null){ modelAndView.addObject("message", "使用者不存在或者密碼錯誤!請重新輸入"); modelAndView.setViewName("error"); }else{ modelAndView.addObject("admin", admin); modelAndView.setViewName("userinfo"); /* * 這為什麼不直接傳一個username,而傳了一個admin, * 是因為在實際開發中,你傳過去的資訊可能不只是username,還有使用者手機號、地址等等 */ //使用cookie AdminCookieUtil.addLoginCookie(admin, response); //使用session //session.setAttribute("adminSession", admin); } return modelAndView; } /*****************************mybatis xml方式解決的問題*******************************/ /** * 根據username或password查詢List<Admin> */ @ResponseBody @RequestMapping("/findAdmin") public List<Admin> findAdmin(@RequestParam(value="username",required=false) String username, @RequestParam(value="password",required=false) String password, @RequestParam("start") int start, @RequestParam("limit") int limit, HttpServletRequest request, HttpSession session){ Admin admin = AdminCookieUtil.getLoginCookie(request); //Admin admin = (Admin) session.getAttribute("adminSession"); if(admin == null){//未登入 return null; } System.out.println(admin.toJson()); List<Admin> adminList = adminService.findAdmin(username, password, start, limit); return adminList; } /** * 插入一個使用者並返回主鍵 * 注意:get請求也會自動裝配(即將前臺傳入的username和password傳入admin) */ @ResponseBody @RequestMapping("/insert") public Admin insertAdminWithBackId(Admin admin){ return adminService.insertAdminWithBackId(admin); } /*************************guava cache******************************/ /** * 根據username查詢List<Admin> */ @ResponseBody @RequestMapping("/findAdminByUsername") public List<Admin> findAdminByUserName(@RequestParam(value="username") String username){ List<Admin> adminList = adminService.findByUsername(username); return adminList; } @ResponseBody @RequestMapping("/findAdminList") public List<Admin> findAdminList(@RequestParam(value="username") String username, @RequestParam(value="password",required=false) String password, @RequestParam("start") int start, @RequestParam("limit") int limit){ List<Admin> adminList = adminService.findAdminList(username, password, start, limit); return adminList; } }
將使用到的兩個方法:
public List<Admin> findAdminByUserName(String username)
public List<Admin> findAdminList(String username, String password, int start, int limit)
3、測試
單元測試:使用springJunit去測就行
整體測試:程式碼寫好之後,注意對程式碼去做測試的方法,先執行相應的controller的方法,然後對查詢出來的部分資料在資料庫中直接進行修改,再執行之前的controller對應的方法。出現兩種結果:
第二次執行與第一次結果相同:快取成功
第二次執行與第一次結果不同:快取不成功
4、總結:
常用的幾個API:
get(Object key):首先獲取value-->若獲取不到,先快取-->再從快取中去取(以上三步是原子操作),使用該方法優先於使用put
getIfPresent(Object key):獲取value,若獲取不到,返回null;若獲取的到,返回value
put(Object key, Object value):顯示的新增快取key-value
guava cache的get(Object key)的value不能為null(這個可以去看原始碼的註釋),看下邊的程式碼例子:
LoadingCache<String, List<Admin>> adminListCache = CacheBuilder.newBuilder() .expireAfterWrite(20, TimeUnit.MINUTES)// 快取20分鐘 .maximumSize(1000)// 最多快取1000個物件 .build(new CacheLoader<String, List<Admin>>() { public List<Admin> load(String username) throws Exception { //1、下邊這樣null的話,不拋異常 /*List<Admin> admins = adminDao.getUserByName(username); if(admins==null){ return null; } return admins;*/ //2、但是如果這裡查詢出來的結果為null的話,也沒關係 //return adminDao.getUserByName(username); //3、如果這裡直接返回null,就會出現com.google.common.cache.CacheLoader$InvalidCacheLoadException return null; } });
注意:該程式碼中的三種null情況,只有第三種會丟擲異常。前兩種不為空的原因是因為,即使admins沒有元素,admins也不會是null,而是[],這應該是mybatis的功勞?!這個是個問題,以後在讀mybatis原始碼的時候,會仔細研究!!!但是實際使用中,我們判斷一個list是否為空,會使用CollectionUtil.isNotEmpty(list)類似於下邊這樣,就會丟擲異常了。
LoadingCache<String, List<Admin>> adminListCache = CacheBuilder.newBuilder() .expireAfterWrite(20, TimeUnit.MINUTES)// 快取20分鐘 .maximumSize(1000)// 最多快取1000個物件 .build(new CacheLoader<String, List<Admin>>() { public List<Admin> load(String username) throws Exception { //1、下邊這樣null的話,不拋異常 List<Admin> admins = adminDao.getUserByName(username); //System.out.println(admins);//如果admins為空,不會返回null,而是返回[] if(CollectionUtils.isEmpty(admins)){ System.out.println(admins+"-->"); return null; } return admins; //2、但是如果這裡查詢出來的結果為null的話,也沒關係 //return adminDao.getUserByName(username); //3、如果這裡直接返回null,就會出現com.google.common.cache.CacheLoader$InvalidCacheLoadException //return null; } });
但是,為了在guava cache的使用中不丟擲異常,我們這裡直接使用下邊這句就好了,由mybatis將[]返回就好了。
return adminDao.getUserByName(username);
免費領取驗證碼、內容安全、簡訊傳送、直播點播體驗包及雲伺服器等套餐
更多網易技術、產品、運營經驗分享請點選。
相關文章:
【推薦】 常見的三種撞庫方法
【推薦】 == vs === in Javascript