继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Mybatis+Redis纯注解方案实现缓存案例

丶包菜
关注TA
已关注
手记 6
粉丝 22
获赞 397

    在网络发展迅速,数据交互分分钟冲爆服务器的年代,三岁小孩都不满足拿着网页乱点还狂按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类的简单实现了,就不再贴代码了。

打开App,阅读手记
25人推荐
发表评论
随时随地看视频慕课网APP

热门评论

您好。我想问一下这种实现方式如何自定义生成的redis的键

我给作者补充一下吧,好让模仿作者demo的读者不用费劲找了,下面是我公司项目中的代码,自个写的,类名是ResourceHelper

57a3f9120001d24105000358.jpg

57a3f91400010a8805000175.jpg


作者,要放代码放全啊,你那读取redis.properties配置文件的代码都没写出来,让一些按照你的demo写一遍的读者浪费一些没必要的时间从网上找

查看全部评论