grail项目中加redis缓存

简单说下我一开始在grails项目中使用redis的过程。

一开始,我根据 这个网站的https://github.com/grails-plugins/grails-redis 提供的方式,使用的是注解的方式进行数据的缓存。我用的可嗨了。结果自测的时候才发现,这里面的注解 (

memoizeHash 只能放String类型的数据,
)

其他的具体的,大家可以进到RedisService里面自己看。我现在主要说说我自己实现的方式。

我拿一个Map 里面放domain和其他数据类型的值来说把。

这是我写的一个方法。可以支持Map里面有domain。Map中有map。

@Transactional
class MemoizeService {

    //用户序列化和反序列化的类
    RedisSerializer valueSerializer;

    // redisService类
    def redisService

    /**
     *
     * 1:存储 List<Map>的数据
     *
     * @param key
     * @param closure
     * @param expire
     * @return
     *
     * 备注:List中的map中不支持domain
     */
    def memoizeListObject(String key, Closure closure, int expire = 0) {
        // 1:查询缓存,
        byte[] keyByte = valueSerializer.serialize(key);
        def list = redisService.withRedis { Jedis redis ->
            if (redis) {
                log.debug("自定义的memoizeListObject方法---根据key获取值。");
                List<byte[]> list = redis.lrange(keyByte, 0, -1);//
                List<Object> value = handleList(list, false);
                //打印日志
                if (value) {
                    log.debug("自定义的memoizeListObject方法---根据key=${key},获取值=${value}");
                }
                return value
            }
        }

        //2:如果缓存中无数据,进行数据库的查询。
        if (!list) {
            //存缓存
            if (log.debugEnabled) log.debug "cache miss: $key"
            list = closure();//调用目标方法,返回值里面,我们需要判断每个值的类型。
            redisService.withRedis { Jedis redis ->
                if (redis) {
                    if (list && list.size() > 0) {
                        List<byte[]> listTemp = handleList((List) list);//序列化
                        redis.rpush(keyByte, (byte[][]) listTemp.toArray());//存入缓存
                        if (expire) {
                            redis.expire(keyByte, expire);//设置缓存时间
                        }
                    }
                }
            }

        } else {
            if (log.debugEnabled) log.debug "cache hit : $key = $list"
        }
        return list //返回值
    }

    /**
     * 2:缓存Map中存储复杂对象的数据
     *  a:支持map中有domain对象
     *  b:支持map中有List<Map>数据
     *  c:未支持map中有map的数据。
     *
     * @param key 缓存数据的key值
     * @param closure 执行对象的目标方法
     * @param expire 缓存时间
     * @return 缓存的map对象/数据库中查询的对象
     */
    def memoizeMap(String key, Closure closure, int expire = 0) {
        //1:序列化key值
        byte[] keyByte = valueSerializer.serialize(key);
        //2:查询缓存
        def hash = redisService.withRedis { Jedis redis ->
            if (redis) {
                log.debug("自定义的memoireMap方法---根据key获取值。");
                Map map = [:];//返回值的map
                Map<byte[], byte[]> hashMap = redis.hgetAll(keyByte);//这个是获取map的所有值的方法
                if (hashMap) {
                    map = deserializeMap(hashMap);
                    log.debug("自定义的memoireMap方法---根据key=${key},获取值=${map}");
                }
                return map
            }
        }
        //3:如果缓存中无数据,就调用目标方法和存储缓存。
        if (!hash) {
            if (log.debugEnabled) log.debug "cache miss: $key"
            hash = closure();//调用目标方法,返回值里面,我们需要判断每个值的类型。
            if (hash) {
                redisService.withRedis { Jedis redis ->
                    if (redis) {
                        Map<byte[], byte[]> tempHash = serializeMap(hash)
                        log.debug("进行数据缓存:键=${key},值=${hash}")
                        redis.hmset(keyByte, tempHash)
                        if (expire) {
                            redis.expire(keyByte, expire)
                        }
                    }
                }
            }
        } else {
            if (log.debugEnabled) log.debug "cache hit : $key = $hash"
        }
        return hash //返回值en
    }

    /**
     *  处理 List 数据
     *
     * @param isSerialize 是否序列化
     * @param list 需要处理的数据
     * @return 返回处理过后的数据
     */
    public List<Object> handleList(List<Object> list, boolean isSerialize = true) {
        //1:作基本判断
        if (!list) {
            return null;//待处理的数据不能为空
        }
        //2:处理数据
        List<Object> targetList = [];
        if (isSerialize) {
            for (Object o : list) {
                targetList.add(valueSerializer.serialize(o))//序列化
            }
        } else {
            for (byte[] bt : list) {
                targetList.add(valueSerializer.deserialize(bt)) //反序列化
            }
        }
        //3;返回数据
        return targetList;
    }

    /**
     *
     * hashMap:待处理的值
     * map :返回的值
     *
     * 反序列化
     */
    private Map deserializeMap(Map hashMap) {
        Map map = [:];
        for (byte[] hashKey : hashMap.keySet()) {
            def _key = valueSerializer.deserialize(hashKey);
            def _value = valueSerializer.deserialize(hashMap[hashKey]);
            if (_value && _value instanceof String && _value.toString().startsWith("DOMAIN#")) { // domain ,可支持
                def parts = _value.toString().split("#");
                map.put(_key, Class.forName(parts[1]).load(parts[2]));//存入键值
            } else if (_value && Map.class.isAssignableFrom(_value.getClass())) {// 有问题,还不能支持
                map.put(_key, _value);//Map
            } else if (_key && _key.toString().contains("List")) { //支持Map中存入List。
                List list = [];
                for (Object obj : (List) _value) {
                    def _obj = valueSerializer.deserialize(obj);
                    if (_obj && _obj instanceof String && _obj.toString().startsWith("DOMAIN#")) { // domain
                        def parts = _obj.toString().split("#");
                        list.add(Class.forName(parts[1]).load(parts[2]));//存入键值
                    } else {
                        list.add(_obj);
                    }
                }
                def parts = _key.toString().split("#");//
                map.put(parts[0], list)
            } else {
                map.put(_key, _value);//存入键值
            }
        }

        return map;
    }

    /**
     *
     * 序列化数据
     *
     * @param hash 待处理的值,
     * @param tempHash 返回的值,Map<byte[], byte[]>
     */
    private Map serializeMap(Map hash) {
        Map tempHash = [:]
        for (Object hashKey : hash.keySet()) {
            def value = hash[hashKey]
            //Map里面有domain
            if (value && value.class?.getAnnotation(Entity.class)) { // domain
                tempHash.put(valueSerializer.serialize(hashKey), valueSerializer.serialize("DOMAIN#${value.class.name}#${value.id}".toString()))
            }
            //Map里面有Map,二层的Map不能支持Domain
            else if (value && Map.class.isAssignableFrom(value.getClass())) { //
                tempHash.put(valueSerializer.serialize(hashKey), valueSerializer.serialize(value))//
            } else if (List.class.isAssignableFrom(value.getClass())) { // 支持Map中存入List
                List list = [];
                for (Object obj : (List) value) {
                    if (obj && obj.getClass()?.getAnnotation(Entity.class)) { // domain
                        list.add(valueSerializer.serialize("DOMAIN#${value.class.name}#${obj.id}".toString()))
                    } else {
                        list.add(valueSerializer.serialize(obj));
                    }
                }
                tempHash.put(valueSerializer.serialize(hashKey + "#List"), valueSerializer.serialize(list))
            }
            //其他情况
            else {
                tempHash.put(valueSerializer.serialize(hashKey), valueSerializer.serialize(hash[hashKey]));
            }
        }
        return tempHash
    }

}

 

调用方式:以调用List<Map>为例。

@Transactional(readOnly = true)
public List<Map> findMaterialAuth(Long materialId, int expire = 3600) {
    return memoizeService.memoizeListObject("detailCacheService_findMaterialAuth_${materialId}", {
        //认证信息
        List<MaterialAuth> materialAuths = MaterialAuth.createCriteria().list {
            eq("material.id", materialId)
            order("id", "asc")
            order("seq", "asc")
        }

        List<Map> materialAuthList = new ArrayList()
        materialAuths.each {
            def materialAuthMap = [:]
            materialAuthMap.put("item", it.item)//认证项目
            materialAuthMap.put("imgUrl", it.imgUrl)//认证图片
            materialAuthMap.put("imgTitle", it.imgTitle)//图片标题
            materialAuthList << materialAuthMap
        }
        return materialAuthList

    }, expire)

}

 

转载于:https://my.oschina.net/u/2469180/blog/883389

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值