开发过程当中会有很是频繁地查询某一类对象,尤为是经过主键查询整个对象的状况。好比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序列化框架。缓存
这个缓存方法固然是简单粗暴的,不少问题都没有考虑到,好比:安全
后两个问题,就须要引入独立的集中缓存方案了,后面继续总结。服务器