開發過程當中會有很是頻繁地查詢某一類對象,尤爲是經過主鍵查詢整個對象的狀況。好比user,對於前端UI來講,極可能展示任何業務列表的時候,都有相關的用戶信息,須要顯示用戶的暱稱、頭像之類的,這是就要把列表中涉及的用戶一個個查出來。前端
傳統的方式是使用數據庫聯合查詢,但若是用戶表很大,和業務表關聯查詢的代價是很高的,並且若是用戶表與業務表不在同一個數據庫實例上,就無法聯合了。另外一種思路就是先查業務表——若是有分頁機制的話,一般結果也就是幾十條,再針對結果集的每一個用戶主鍵,一一查詢對應的用戶信息。後者的好處是查詢壓力是可控的,不至於讓數據庫爆掉;缺點在於對數據庫的查詢請求仍是過於頻繁。java
在這種狀況下,若是用戶信息不常常變更,就能夠將其緩存起來,每次從緩存中獲取數據,從而減輕數據庫壓力。Java中最簡單的內存緩存實現就是用HashMap,以數據庫主鍵爲key,整個對象序列化之後的字符串做爲value。但HashMap不是線程安全的,併發狀況下,可能出現意想不到的錯誤,因此應該是用concurrent·包中的ConcurrentHashMap類實現。代碼示例以下:sql
package com.nuanxinli.cache; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.nutz.dao.Dao; import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; import com.nuanxinli.bo.instance.User; @IocBean public class UserCache { private ConcurrentMap<String, User> userMap = new ConcurrentHashMap<String, User>(); @Inject("refer:system_dao") private Dao dao; public User get(String username) { User user = userMap.get(username); if (user == null) { user = dao.fetch(User.class, username); userMap.put(username, user); } return user; } public void updateOneUser(User user) { userMap.put(user.getUsername(),user); } }
從代碼邏輯能夠看出,調用get方法時,首先從map裏查找,若是map中沒有,再從數據庫裏取,而且把結果加入到緩存map中,下次在使用便可直接從map中取到。另外,提供了一個updateOneUser方法,以便在用戶信息發生變化時更新緩存。下面是使用UserCache的例子數據庫
package com.nuanxinli.logic.livecast; import java.util.List; import org.nutz.dao.Chain; import org.nutz.dao.Cnd; import org.nutz.dao.Dao; import org.nutz.dao.QueryResult; import org.nutz.dao.pager.Pager; import org.nutz.dao.sql.Criteria; import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; import com.nuanxinli.application.ImHttpException; import com.nuanxinli.bo.instance.livecast.LiveComment; import com.nuanxinli.cache.UserCache; import com.nuanxinli.util.StrUtil; @IocBean public class LiveCommentLogic { @Inject("refer:gold_dao") private Dao goldDao; @Inject private UserCache userCache; public QueryResult getList(Integer liveId, String type, Integer pageNum, Integer pageSize) { //查詢業務對象列表 Criteria cri = Cnd.cri(); if (StrUtil.isNotNullOrBlank(type)) { cri.where().and("type", "=", type); } cri.where().and("is_deleted", "=", 0).and("live_id", "=", liveId); Pager pager = goldDao.createPager(pageNum, pageSize); List<LiveComment> list = goldDao.query(LiveComment.class, cri, pager); pager.setRecordCount(goldDao.count(LiveComment.class, cri)); //遍歷列表,把其中的用戶信息補全 for (LiveComment liveComment : list) { liveComment.setCreateUser(userCache.get(liveComment.getCreator())); } return new QueryResult(list, pager); } }
這裏的代碼使用了Nutz的ioc、dao和Json序列化框架。緩存
這個緩存方法固然是簡單粗暴的,不少問題都沒有考慮到,好比:安全
後兩個問題,就須要引入獨立的集中緩存方案了,後面繼續總結。服務器