在网络发展迅速,数据交互分分钟冲爆服务器的年代,三岁小孩都不满足拿着网页乱点还狂按F5了,他开始抢着红包点着赞,迷路了还会用百度地图。
作为一只关系型在后台苦不堪言啊!
mysql:”你特么刷什么?”,oracle:”都说了无聊也别乱点啊你!”。
所以就有了gzip压缩这种减小数据体积的玩意,也有了缓存这种东西。
但是频繁的抢啊刷啊关系型数据库还是亚历山大啊,于是追求更高更快更强的我们,这次试着用redis+mybatis来实现缓存。
想想Mybatis这只强大的框架,怎么可能没有缓存这玩意呢。人家随身自带一级缓存,可是呀也就个session级别,自认为速度杠杠的,客户端一关就游戏结束。
一级都出马了,二级也要登场呀。MyBatis开启二级缓存的方式也很简单,在其配置文件中加入以下即可。
<setting name="cacheEnabled" value="true"/>
再在其映射的xml文件中简单
<cache/>
如此,一只Application级别的二级缓存就完成了。
那么redis就可以在这个时候闪亮登场了,Mybatis默认的二级缓存一般的需求还是够用的,Redis想要强行插入那就得按它的规矩,实现其Cache接口。
package com.hcq.dao.mybatis.cache;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.ibatis.cache.Cache;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import com.hcq.dao.redis.RedisPool;
import redis.clients.jedis.Jedis;
public class RedisCache implements Cache{
private static Logger logger = LogManager.getLogger(RedisCache.class);//日志管理
private String id;
private Jedis redisClient=createRedis(); //创建一个jedis连接
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); //读写锁
public void setReadWriteLock(ReadWriteLock readWriteLock) {
this.readWriteLock = readWriteLock;
}
public RedisCache(String id) {
if(id==null){
throw new IllegalArgumentException("Cache instance requires an ID");
}
logger.debug("create an cache instance with id"+id);
this.id=id;
}
public String getId() {
return this.id;
}
/**从连接池中取
* @return
*/
private static Jedis createRedis() {
//从连接池获取redis连接
Jedis jedis =RedisPool.getPool().getResource();
return jedis;
}
public void putObject(Object key, Object value) {
byte[] keybyte=SerializableUtil.serialize(key);
byte[]valuebyte=SerializableUtil.serialize(value);
this.redisClient.set(keybyte, valuebyte);
}
public Object getObject(Object key) {
//缓存穿透
byte[] values=this.redisClient.get(SerializableUtil.serialize(key));
//算法:计算一定时间内没有命中的键,存起来 key->value
if(values==null){
return null;
}
Object obj =SerializableUtil.unserizlize(values);
return obj;
}
public Object removeObject(Object key) {
byte[]keybyte=SerializableUtil.serialize(key);
return this.redisClient.expire(keybyte, 0);
}
public void clear() {
this.redisClient.flushDB();
}
public int getSize() {
Long size = this.redisClient.dbSize();
int s =Integer.valueOf(size+"");
return s;
}
public ReadWriteLock getReadWriteLock() {
return readWriteLock;
}
}
然后就是一个redis连接池,方便获取redis连接和管理。
package com.hcq.dao.redis;
import java.util.ResourceBundle;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class RedisPool {
private static JedisPool pool;
private RedisPool(){
ResourceBundle bundle =ResourceBundle.getBundle("redis");
//bundle类似一个map
if(bundle==null){
throw new IllegalArgumentException("[redis.properties] is not find ");
}
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(Integer.valueOf(bundle.getString("redis.pool.maxActive")));
config.setMaxIdle(Integer.valueOf(bundle.getString("redis.pool.maxIdle")));
config.setMaxWaitMillis(Long.valueOf(bundle.getString("redis.pool.maxWait")));
config.setTestOnBorrow(Boolean.valueOf(bundle.getString("redis.pool.testOnBorrow")));
config.setTestOnReturn(Boolean.valueOf(bundle.getString("redis.pool.testOnReturn")));
//创建连接池
pool =new JedisPool(config,bundle.getString("redis.ip"),Integer.valueOf(bundle.getString("redis.port")));
}
public synchronized static JedisPool getPool() {
if(pool==null){
new RedisPool();
}
return pool;
}
}
连接池需要读取的文件配置,redis.properties。
redis.pool.maxActive=1024
redis.pool.maxIdle=200
redis.pool.maxWait=1000
redis.pool.testOnBorrow=true
redis.pool.testOnReturn=true
redis.ip=127.0.0.1 //本机
redis.port=6379 //默认端口
这里做一个简单的查询,查询所有的电影类型。在bean层,定义一个电影类型对象,必须实现序列化接口。
package com.hcq.bean;
import java.io.Serializable;
public class Mtype implements Serializable{
private static final long serialVersionUID = 1590366991914489696L;
private int tid;
private String tname;
public int getTid() {
return tid;
}
public void setTid(int tid) {
this.tid = tid;
}
public String getTname() {
return tname;
}
public void setTname(String tname) {
this.tname = tname;
}
@Override
public String toString() {
return "Mtype [tid=" + tid + ", tname=" + tname + "]";
}
}
redis的存对象需将其序列化,而查到的数据又通过反序列化成为对象,下面是个序列化工具类。
package com.hcq.dao.mybatis.cache;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerializableUtil {
//序列化
public static byte [] serialize(Object obj){
ObjectOutputStream obi=null;
ByteArrayOutputStream bai=null;
byte[] bs=null;
try {
bai=new ByteArrayOutputStream();
obi=new ObjectOutputStream(bai);
obi.writeObject(obj);
bs=bai.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(bai!=null){
try{
bai.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
return bs;
}
//反序列化
public static Object unserizlize(byte[] bs){
ByteArrayInputStream bis=null;
Object obj=null;
try {
bis=new ByteArrayInputStream(bs);
ObjectInputStream ois=new ObjectInputStream(bis);
obj=ois.readObject();
} catch (Exception e) {
e.printStackTrace();
}finally{
if(bis!=null){
try{
bis.close();
}catch (IOException e) {
e.printStackTrace();
}
}
}
return obj;
}
}
然后在Dao层,使用注解方案配置自定义二级缓存,及其实现类。
package com.hcq.dao;
import java.util.List;
import org.apache.ibatis.annotations.CacheNamespace;
import org.apache.ibatis.annotations.Select;
import com.hcq.bean.Mtype;
@CacheNamespace(implementation=(com.hcq.dao.mybatis.cache.RedisCache.class))
public interface MtypeDao {
@Select("select tname,tid,from Mtype")
public List<Mtype>findAllMtype();
}
至此,一个用redis+mybatis做的缓存就基本实现了。最后的操作就剩下前台和action类的简单实现了,就不再贴代码了。
热门评论
您好。我想问一下这种实现方式如何自定义生成的redis的键
我给作者补充一下吧,好让模仿作者demo的读者不用费劲找了,下面是我公司项目中的代码,自个写的,类名是ResourceHelper
作者,要放代码放全啊,你那读取redis.properties配置文件的代码都没写出来,让一些按照你的demo写一遍的读者浪费一些没必要的时间从网上找