阿里redis缓存

/*************************************************************************
 *                  HONGLING CAPITAL CONFIDENTIAL AND PROPRIETARY
 *
 *                COPYRIGHT (C) HONGLING CAPITAL CORPORATION 2012
 *    ALL RIGHTS RESERVED BY HONGLING CAPITAL CORPORATION. THIS PROGRAM
 * MUST BE USED  SOLELY FOR THE PURPOSE FOR WHICH IT WAS FURNISHED BY
 * HONGLING CAPITAL CORPORATION. NO PART OF THIS PROGRAM MAY BE REPRODUCED
 * OR DISCLOSED TO OTHERS,IN ANY FORM, WITHOUT THE PRIOR WRITTEN
 * PERMISSION OF HONGLING CAPITAL CORPORATION. USE OF COPYRIGHT NOTICE
 * DOES NOT EVIDENCE PUBLICATION OF THE PROGRAM.
 *                  HONGLING CAPITAL CONFIDENTIAL AND PROPRIETARY
 *************************************************************************/

package com.hongling.common.cache;

import com.hongling.common.exception.CacheException;
import com.hongling.common.util.CommonUtils;
import org.apache.commons.io.Charsets;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import redis.clients.jedis.Jedis;

import java.util.Date;
import java.util.Set;

/**
 * 缓存中存储会话。
*
 * @author Yelin.G at 2015/08/03
 */
public class CacheSessionStorage extends CacheStorageAdapter {

    protected static final Logger LOG = LogManager.getLogger(CacheSessionStorage.class);

    protected JedisClient jedisClient;

    public  static final String USER_LIMT_LOCK_KEY="USER_LIMT_LOCK_";

    public CacheSessionStorage() {
        super();
    }

    public CacheSessionStorage(JedisClient jedisClient) {
        super();
        this.jedisClient = jedisClient;
    }

    /**
     * 保存数据在缓存中。
*
     * @param key 键。
* @param value 值。
* @param expiredTime 过期时间。
*/
@Override
public void set(String key, Object value, int expiredTime, Jedis jedis) {
        if(value instanceof String) {
            jedis.set(key, (String) value);
            jedis.expire(key, expiredTime);
        } else {
            try {
                jedis.set(key.getBytes("utf8"), CommonUtils.objectToByte(value));
                jedis.expire(key, expiredTime);
            } catch (Exception ex) {
                LOG.error("设置kv-store值失败:{}={}", key, value);
                throw new CacheException(ex);
            }
        }
    }

    /**
     * 保存数据在缓存中。
*
     * @param key 键。
* @param value 值。
*/
@Override
public void set(String key, Object value, Jedis jedis) {
        if(value instanceof String) {
            jedis.set(key, (String) value);
        } else {
            try {
                jedis.set(key.getBytes("utf8"), CommonUtils.objectToByte(value));
            } catch (Exception ex) {
                LOG.error("设置kv-store值失败:{}={}", key, value);
                throw new CacheException(ex);
            }
        }
    }

    /**
     * 保存数据在缓存中。
*
     * @param key 键。
* @param value 值。
* @param expiredTime 过期时间。
*/
@Override
public void setAndClose(String key, Object value, int expiredTime) {
        Jedis jedis = null;
        try {
            jedis = jedisClient.getJedis();
            set(key, value, expiredTime, jedis);
        } finally {
            if(jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 保存数据在缓存中。
*
     * @param key 键。
* @param value 值。
*/
@Override
public void setAndClose(String key, Object value) {
        Jedis jedis = null;
        try {
            jedis = jedisClient.getJedis();
            set(key, value, jedis);
        } finally {
            if(jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 保存数据在缓存中。
*
     * @param key 键。
* @param value 值。
* @param expiredTime 过期时间。
*/
@Override
public void set(String key, Object value, Date expiredTime, Jedis jedis) {
        Long expire = expiredTime.getTime() - System.currentTimeMillis();
        if(expire > Integer.MAX_VALUE * 1000){
            set(key, value, Integer.MAX_VALUE, jedis);
        }
        set(key, value, expire.intValue()/1000, jedis);
    }

    /**
     * 保存数据在缓存中。
*
     * @param key 键。
* @param value 值。
* @param expiredTime 过期时间。
*/
@Override
public void setAndClose(String key, Object value, Date expiredTime) {
        Jedis jedis = null;
        try {
            jedis = jedisClient.getJedis();
            set(key, value, expiredTime, jedis);
        } finally {
            if(jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 从缓存中获取数据。
*
     * @param key 键。
* @return 缓存中数据。
*/
@Override
public String get(String key, Jedis jedis) {
        return jedis.get(key);
    }

    /**
     * 从缓存中获取数据。
*
     * @param key 键。
* @return 缓存中数据。
*/
@Override
public String getAndClose(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisClient.getJedis();
            return jedis.get(key);
        } finally {
            if(jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 从缓存中获取数据。
*
     * @param key 键。
* @return 缓存中数据。
*/
@Override
public Object get(byte[] key, Jedis jedis) {
        try {
            return CommonUtils.byteToObject(jedis.get(key));
        } catch (Exception ex) {
            LOG.error("获取kv-store值失败:key={}", new String(key, Charsets.UTF_8));
            throw new CacheException(ex);
        }
    }

    /**
     * 从缓存中获取数据。
*
     * @param key 键。
* @return 缓存中数据。
*/
@Override
public Object getAndClose(byte[] key) {
        Jedis jedis = null;
        try {
            jedis = jedisClient.getJedis();
            return get(key, jedis);
        } finally {
            if(jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 将缓存中的数据增加1*
     * @param key 键。
* @param jedis {@link redis.clients.jedis.Jedis}
     * @return 计算后缓存的值。
*/
public Long increase(String key, Jedis jedis) {
        return jedis.incr(key);
    }

    /**
     * 将缓存中的数据增加1*
     * @param key 键。
* @return 计算后缓存的值。
*/
public Long increaseAndClose(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisClient.getJedis();
            return jedis.incr(key);
        } finally {
            if(jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 将缓存中的数据减去1*
     * @param key 键。
* @param jedis {@link redis.clients.jedis.Jedis}
     * @return 计算后缓存的值。
*/
public Long decrease(String key, Jedis jedis) {
        return jedis.decr(key);
    }

    /**
     * 将缓存中的数据减去1*
     * @param key 键。
* @return 计算后缓存的值。
*/
public Long decreaseAndClose(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisClient.getJedis();
            return jedis.decr(key);
        } finally {
            if(jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 将缓存中的数据增加指定值。
*
     * @param key 键。
* @param num 增加的数值。
* @param jedis {@link redis.clients.jedis.Jedis}
     * @return 计算后缓存的值。
*/
public Long increaseBy(String key, long num, Jedis jedis) {
        return jedis.incrBy(key, num);
    }

    /**
     * 将缓存中的数据增加指定值。
*
     * @param key 键。
* @param num 增加的数值。
* @return 计算后缓存的值。
*/
public Long increaseByAndClose(String key, long num) {
        Jedis jedis = null;
        try {
            jedis = jedisClient.getJedis();
            return jedis.incrBy(key, num);
        } finally {
            if(jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 将缓存中的数据减去指定值。
*
     * @param key 键。
* @param num 增加的数值。
* @param jedis {@link redis.clients.jedis.Jedis}
     * @return 计算后缓存的值。
*/
public Long decreaseBy(String key, long num, Jedis jedis) {
        return jedis.decrBy(key, num);
    }

    /**
     * 将缓存中的数据减去指定值。
*
     * @param key 键。
* @param num 增加的数值。
* @return 计算后缓存的值。
*/
public Long decreaseByAndClose(String key, long num) {
        Jedis jedis = null;
        try {
            jedis = jedisClient.getJedis();
            return jedis.decrBy(key, num);
        } finally {
            if(jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 从缓存中移除数据。
*
     * @param key 键。
* @return {@link Long}*/
@Override
public Long remove(String key, Jedis jedis) {
        return jedis.del(key);
    }

    /**
     * 从缓存中移除数据。
*
     * @param key 键。
* @return {@link Long}*/
@Override
public Long removeAndClose(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisClient.getJedis();
            return jedis.del(key);
        } finally {
            if(jedis != null) {
                jedis.close();
            }
        }
    }

    /************************************SET集合操作start************************************************/
    /**
     * 将字符串数据放入SET集合中。
*
     * @param key       键。
* @param values    数据集合。
* @return {@link Long}*/
@Override
public Long addToSet(String key, String... values) {
        Jedis jedis = null;
        try {
            jedis = jedisClient.getJedis();
            return jedis.sadd(key, values);
        } finally {
            if(jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 将字符串数据放入SET集合中。
*
     * @param key       键。
* @param expiredTime 过期时间。
* @param values    数据集合。
* @return {@link Long}*/
@Override
public Long addToSet(String key, int expiredTime, String... values) {
        Jedis jedis = null;
        try {
            jedis = jedisClient.getJedis();
            Long sadd = jedis.sadd(key, values);
            jedis.expire(key, expiredTime);
            return sadd;
        } finally {
            if(jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 将指定字符串数据移除SET集合中。
*
     * @param key       键。
* @param values    数据集合。
* @return {@link Long}*/
@Override
public Long removeFromSet(String key, String... values) {
        Jedis jedis = null;
        try {
            jedis = jedisClient.getJedis();
            return jedis.srem(key, values);
        } finally {
            if(jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 检测指定字符串数据是否在SET集合中。
*
     * @param key       键。
* @param value    数据集合。
* @return {@link java.lang.Boolean}*/
@Override
public Boolean isMemberInSet(String key, String value) {
        Jedis jedis = null;
        try {
            jedis = jedisClient.getJedis();
            return jedis.sismember(key, value);
        } finally {
            if(jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 检测指定字符串数据是否在SET集合中。
*
     * @param key       键。
* @return {@link java.util.Set}*/
@Override
public Set<String> getAllMembersInSet(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisClient.getJedis();
            return jedis.smembers(key);
        } finally {
            if(jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * 查询指定KeySET集合数量。
*
     * @param key       键。
* @return {@link java.lang.Long}*/
@Override
public Long getMemberCountInSet(String key) {
        Jedis jedis = null;
        try {
            jedis = jedisClient.getJedis();
            return jedis.scard(key);
        } finally {
            if(jedis != null) {
                jedis.close();
            }
        }
    }


    /************************************SET集合操作end************************************************/

    /**
     * 关闭连接。
*
     */
public void close(Jedis jedis) {
        if(jedis != null) {
            jedis.close();
        }
    }

    /**
     * jedis获取锁。
*
     * @param key  键。
* @return
*/
public boolean lock(String key,String value){
        Jedis jedis = null;
        try {
            jedis = jedisClient.getJedis();
            if(jedis.setnx(key,value) == 1){
                jedis.expire(key,60*5); //默认5分钟
return true;
            }else {
                return false;
            }
        } finally {
            if(jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * jedis获取锁。
*
     * @param key  键。
* @return
*/
public boolean lock(String key){
        return this.lock(key,"1");
    }

    /**
     * jedis释放锁
*
     * @param key  键。
* @return
*/
public Long unlock(String key){
       return removeAndClose(key);
    }


    /**
     * 设置{@link com.hongling.common.cache.JedisClient}*
     * @param jedisClient {@link com.hongling.common.cache.JedisClient}*/
public void setJedisClient(JedisClient jedisClient) {
        this.jedisClient = jedisClient;
    }

    /**
     * 获取{@link redis.clients.jedis.Jedis}*
     */
public Jedis getJedis() {
        return jedisClient.getJedis();
    }
}
在数据库更新时通知 Redis 缓存进行同步,可以采用多种策略,这些策略在实现复杂度、一致性保证、系统耦合度和时效性方面各有不同。以下是几种常见的实现方式: ### 1. 同步双写 在更新数据库的同时直接更新 Redis 缓存。这种方式可以确保数据库和缓存之间保持强一致性,但会对代码造成一定的侵入性,并增加系统的耦合度。适用于对数据一致性要求较高的场景。 ```java public void updateDataWithSyncWrite(String key, String newValue) { // 更新数据库 updateDatabase(key, newValue); // 更新 Redis 缓存 jedis.set(key, newValue); } ``` 同步双写的优势在于时效性强,缓存与数据库保持强一致性。然而,这种方式可能会增加代码复杂度,同时需要处理数据库和缓存更新失败的情况,例如事务回滚或 Redis 连接失败。 ### 2. 异步通知 在更新数据库时发送事件通知,由监听服务接收事件并更新 Redis 缓存。这种方式通常通过消息队列(如 Kafka、RabbitMQ 或 RocketMQ)来实现,可以降低系统的耦合度,并支持多个缓存服务的同步[^2]。 具体实现流程如下: - 数据库更新后,将更新事件发布到消息队列。 - Redis 缓存服务监听队列中的事件,并根据事件内容更新缓存。 异步通知的优点在于低耦合和可扩展性,但存在一定的延迟,可能导致短时间内数据库和缓存数据不一致。适用于对时效性要求不高的场景。 ### 3. 基于 Canal 的数据库变更监听 Canal 是阿里巴巴开源的一个 MySQL 数据库增量日志解析与订阅组件。通过 Canal,可以实时监听数据库的变更,并触发 Redis 缓存的更新或删除操作。以下是一个使用 Canal 的示例: ```java @CanalTable("tb_item") @Component public class ItemHandler implements EntryHandler<Item> { @Autowired private RedisHandler redisHandler; @Autowired private Cache<Long, Item> itemCache; @Override public void insert(Item item) { // 写数据到 JVM 进程缓存 itemCache.put(item.getId(), item); // 写数据到 Redis redisHandler.saveItem(item); } @Override public void update(Item before, Item after) { // 更新 JVM 缓存 itemCache.put(after.getId(), after); // 更新 Redis 缓存 redisHandler.saveItem(after); } @Override public void delete(Item item) { // 删除 JVM 缓存 itemCache.invalidate(item.getId()); // 删除 Redis 缓存 redisHandler.deleteItemById(item.getId()); } } ``` 通过 Canal,可以实现数据库变更自动同步到 Redis,减少代码侵入性,并提升系统的实时性和一致性。 ### 4. 设置缓存过期时间 为缓存设置一个合理的过期时间,当缓存过期后,下次查询会触发从数据库加载新数据并更新缓存。这种方式实现简单,但存在时效性问题,在缓存未过期前可能导致数据不一致。 ```java public void setCacheWithExpire(String key, String value, int expireTimeInSeconds) { jedis.setex(key, expireTimeInSeconds, value); } ``` 此方法适用于更新频率较低、对数据一致性要求不高的业务场景。 ### 5. 读取时更新(Read-Through Caching) 在读取缓存时,如果发现缓存未命中,则从数据库加载数据并写入缓存。这种方式可以确保缓存中的数据始终是最新的,但首次缓存未命中时会有额外的延迟。 ```java public String getDataWithReadThrough(String key) { String value = jedis.get(key); if (value == null) { // 缓存未命中,从数据库查询 value = queryFromDatabase(key); if (value != null) { jedis.setex(key, DEFAULT_EXPIRE_TIME, value); // 设置缓存 } } return value; } ``` 读取时更新策略可以有效减少缓存与数据库的不一致时间,但会增加数据库的负载。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值