redis 使用示例
使用示例
示例 1:设置和获取字符串值
public class StringValueExample {
public static void main(String[] args) {
// 获取 RedisCache 实例
RedisCache redisCache = Redis.use();
// 设置键值对
redisCache.set("myKey", "myValue");
// 获取值
String value = redisCache.get("myKey");
System.out.println("The value of 'myKey' is: " + value);
// 设置带有过期时间的键值对
redisCache.setex("expiringKey", 60, "expiringValue"); // 60秒后过期
// 获取值
String expiringValue = redisCache.get("expiringKey");
System.out.println("The value of 'expiringKey' is: " + expiringValue);
}
}
示例 2:操作整数值
public class IntegerValueExample {
public static void main(String[] args) {
// 获取 RedisCache 实例
RedisCache redisCache = Redis.use();
// 设置整数值
redisCache.setInt("intKey", 100);
// 获取整数值
Integer intValue = redisCache.getInt("intKey");
System.out.println("The value of 'intKey' is: " + intValue);
// 增加整数值
redisCache.incrBy("intKey", 50);
intValue = redisCache.getInt("intKey");
System.out.println("The value of 'intKey' after increment is: " + intValue);
// 减少整数值
redisCache.decrBy("intKey", 30);
intValue = redisCache.getInt("intKey");
System.out.println("The value of 'intKey' after decrement is: " + intValue);
}
}
示例 3:操作哈希表
public class HashValueExample {
public static void main(String[] args) {
// 获取 RedisCache 实例
RedisCache redisCache = Redis.use();
// 设置哈希表字段
redisCache.hset("user:1001", "name", "John Doe");
redisCache.hset("user:1001", "age", 30);
// 获取哈希表字段的值
String name = redisCache.hget("user:1001", "name");
Integer age = redisCache.hget("user:1001", "age");
System.out.println("User 1001 Name: " + name);
System.out.println("User 1001 Age: " + age);
// 获取整个哈希表
Map<String, Object> user = redisCache.hgetAll("user:1001");
System.out.println("User 1001 Details: " + user);
}
}
示例 3:将对象存入哈希表
import java.util.ArrayList;
import java.util.List;
import com.litongjava.jfinal.plugins.model.User;
import com.litongjava.redis.Redis;
import com.litongjava.redis.RedisPlugin;
public class HashDemoWithUser {
public static void main(String[] args) {
// 用于缓存bbs模块的redis服务
RedisPlugin bbsRedis = new RedisPlugin("main", "192.168.3.9", 6379, 3000, "123456");
bbsRedis.start();
List<User> list = new ArrayList<>();
list.add(new User("Tong Li", "0000000"));
list.add(new User("Tong Li1", "0000000"));
// set list
Redis.use().hsetList("user", "001", list);
// get list
List<User> hgetList = Redis.use().hgetList("user", "001", User.class);
System.out.println(hgetList.size());
bbsRedis.stop();
}
}
示例 5:操作列表
public class ListValueExample {
public static void main(String[] args) {
// 获取 RedisCache 实例
RedisCache redisCache = Redis.use();
// 将元素压入列表头部
redisCache.lpush("myList", "element1", "element2", "element3");
// 从列表尾部弹出元素
String element = redisCache.rpop("myList");
System.out.println("Popped element from myList: " + element);
// 获取列表中的所有元素
List<String> elements = redisCache.lrange("myList", 0, -1);
System.out.println("All elements in myList: " + elements);
}
}
示例 6:检查键是否存在
public class KeyExistenceExample {
public static void main(String[] args) {
// 获取 RedisCache 实例
RedisCache redisCache = Redis.use();
// 设置一个键值对
redisCache.set("someKey", "someValue");
// 检查键是否存在
boolean exists = redisCache.hasKey("someKey");
System.out.println("Does 'someKey' exist? " + exists);
// 删除键
redisCache.del("someKey");
// 再次检查键是否存在
exists = redisCache.hasKey("someKey");
System.out.println("Does 'someKey' exist after deletion? " + exists);
}
}
示例 7:发布和订阅消息
public class PubSubExample {
public static void main(String[] args) {
// 获取 RedisCache 实例
RedisCache redisCache = Redis.use();
// 订阅一个频道
new Thread(() -> {
redisCache.subscribe(new JedisPubSub() {
@Override
public void onMessage(String channel, String message) {
System.out.println("Received message: " + message + " from channel: " + channel);
}
}, "myChannel");
}).start();
// 发布消息到频道
redisCache.publish("myChannel", "Hello, Redis!");
}
}
示例 8:使用 Redis 脚本执行操作
public class ScriptExecutionExample {
public static void main(String[] args) {
// 获取 RedisCache 实例
RedisCache redisCache = Redis.use();
// Lua 脚本示例:获取一个键的值并设置一个新值
String script = "local value = redis.call('get', KEYS[1]); " +
"redis.call('set', KEYS[2], ARGV[1]); " +
"return value;";
// 执行 Lua 脚本
Object result = redisCache.eval(script, 2, "key1", "key2", "newValue");
System.out.println("Result of script execution: " + result);
}
}
示例 9:使用扫描命令查找匹配的键
public class ScanKeysExample {
public static void main(String[] args) {
// 获取 RedisCache 实例
RedisCache redisCache = Redis.use();
// 扫描匹配的键
redisCache.scan(0, "user:*", 10, keys -> {
System.out.println("Found keys: " + keys);
return true; // 返回 true 继续扫描,返回 false 停止扫描
});
}
}
示例 10:获取随机元素(集合操作)
public class SetOperationsExample {
public static void main(String[] args) {
// 获取 RedisCache 实例
RedisCache redisCache = Redis.use();
// 添加元素到集合
redisCache.sadd("mySet", "element1", "element2", "element3");
// 获取集合中的随机元素
String randomElement = redisCache.srandmember("mySet");
System.out.println("Random element from mySet: " + randomElement);
// 获取集合中的所有元素
Set<String> elements = redisCache.smembers("mySet");
System.out.println("All elements in mySet: " + elements);
}
}
示例 11:为键设置过期时间
public class ExpireKeyExample {
public static void main(String[] args) {
// 获取 RedisCache 实例
RedisCache redisCache = Redis.use();
// 设置键值对
redisCache.set("tempKey", "tempValue");
// 设置键的过期时间为 30 秒
redisCache.expire("tempKey", 30);
// 检查剩余时间
Long ttl = redisCache.ttl("tempKey");
System.out.println("TTL of 'tempKey': " + ttl + " seconds");
}
}
示例 12 :使用 RedisCache.lock 进行分布式锁
public class DistributedLockExample {
public static void main(String[] args) {
// 获取 RedisCache 实例
RedisCache redisCache = Redis.use();
// 定义锁的名称
String lockName = "distributed_lock";
// 锁的超时时间,单位:秒
int lockExpireTime = 120; // 锁的过期时间为 120 秒
// 获取锁的等待时间,单位:秒
int lockTimeout = 5; // 如果在 5 秒内没有获取到锁,则放弃
// 尝试获取锁
String lockId = redisCache.lock(lockName, lockExpireTime, lockTimeout);
if (lockId != null) {
try {
// 成功获取到锁,执行需要保护的业务逻辑
System.out.println("成功获取锁,正在执行业务逻辑...");
// 业务逻辑代码
performBusinessLogic();
} finally {
// 释放锁
redisCache.unlock(lockName, lockId);
System.out.println("锁已释放。");
}
} else {
// 未能获取到锁
System.out.println("未能获取锁,可能另一个进程持有该锁。");
}
}
private static void performBusinessLogic() {
// 模拟业务逻辑的执行
try {
Thread.sleep(3000); // 假设业务逻辑需要 3 秒钟才能执行完毕
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("业务逻辑执行成功。");
}
}
代码说明
获取
RedisCache
实例:- 通过
Redis.use()
获取RedisCache
实例。
- 通过
定义锁相关参数:
lockName
: 锁的名称,通常与业务逻辑相关联。lockExpireTime
: 锁的过期时间,设置为 120 秒。lockTimeout
: 尝试获取锁的超时时间,设置为 5 秒。
尝试获取分布式锁:
- 调用
redisCache.lock(lockName, lockExpireTime, lockTimeout)
尝试获取锁。 - 如果成功获取到锁,返回
lockId
;否则返回null
。
- 调用
执行业务逻辑:
- 在成功获取锁后,执行需要保护的业务逻辑。
释放锁:
- 在业务逻辑执行完毕后,调用
redisCache.unlock(lockName, lockId)
释放锁。
- 在业务逻辑执行完毕后,调用
注意事项
- 分布式锁通常用于确保在分布式环境下,多个进程不会同时执行同一段代码,从而避免资源竞争导致的数据不一致问题。
- 在高并发场景下,设置合理的锁过期时间和获取锁的超时时间非常重要。
示例 12 :使用 RedisCache
的 withLock
方法进行分布式锁
以下是一个使用 RedisCache
的 withLock
方法进行分布式锁的示例。withLock
方法会自动处理锁的获取和释放逻辑,用户只需专注于需要加锁的业务逻辑。
public class DistributedLockWithLockMethodExample {
public static void main(String[] args) {
// 获取 RedisCache 实例
RedisCache redisCache = Redis.use();
// 定义锁的名称
String lockName = "distributed_lock_with_withLock";
// 锁的超时时间,单位:秒
int lockExpireTime = 120; // 锁的过期时间为 120 秒
// 获取锁的等待时间,单位:秒
int lockTimeout = 5; // 如果在 5 秒内没有获取到锁,则放弃
// 使用 withLock 方法执行加锁的业务逻辑
boolean success = redisCache.withLock(lockName, lockExpireTime, lockTimeout, () -> {
// 业务逻辑代码,这段代码在获取锁后执行
System.out.println("成功获取锁,正在执行业务逻辑...");
performBusinessLogic();
});
if (success) {
System.out.println("业务逻辑执行完毕,锁已释放。");
} else {
System.out.println("未能获取锁,可能另一个进程持有该锁。");
}
}
private static void performBusinessLogic() {
// 模拟业务逻辑的执行
try {
Thread.sleep(3000); // 假设业务逻辑需要 3 秒钟才能执行完毕
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("业务逻辑执行成功。");
}
}
代码说明
获取
RedisCache
实例:- 通过
Redis.use()
获取RedisCache
实例。
- 通过
定义锁相关参数:
lockName
: 锁的名称,用于标识此锁。lockExpireTime
: 锁的过期时间,设置为 120 秒。lockTimeout
: 尝试获取锁的超时时间,设置为 5 秒。
使用
withLock
方法加锁执行业务逻辑:- 调用
redisCache.withLock(lockName, lockExpireTime, lockTimeout, () -> { ... })
,并在 Lambda 表达式中编写需要保护的业务逻辑。 - 如果成功获取锁并执行业务逻辑,则返回
true
;否则返回false
。
- 调用
锁的自动释放:
withLock
方法会在业务逻辑执行完毕后自动释放锁,因此不需要手动调用unlock
。
使用 withLock
方法的优点
- 简洁易用:
withLock
方法封装了锁的获取、业务逻辑的执行和锁的释放,简化了代码。 - 自动释放锁:即使在业务逻辑抛出异常的情况下,
withLock
方法也能确保锁被正确释放,避免死锁问题。
防止重复提交
问题
在接口 bindUser
中,为了防止前端重复提交设备标识 userEquipment
,使用 Redis 的 SET
数据结构,检测是否已经存在重复提交:
解决办法:
- 在 Redis 中使用
SET
数据结构存储设备标识userEquipment
,并设置 120 秒的过期时间 - 检测设备标识是否已经存在于 Redis 集合中
实现方法:使用 SISMEMBER
检查去重
Redis 的 SISMEMBER
是一种高效的去重检查方式。我们可以在接收到请求时,直接判断设备码是否已存在,如果存在,则阻止继续提交,避免重复请求。只需通过 SISMEMBER
检查,避免了原子性问题。
boolean isExist = Redis.use().sismember(RedisKeys.equipment_submitted, userEquipment);
if (isExist) {
return ResponseResult.fail("重复提交,请等待");
}
Redis.use().sadd(RedisKeys.equipment_submitted, userEquipment); // 保存设备码
Redis.use().expire(RedBookRedisKeys.equipment_submitted, 120); //120秒后过期
SISMEMBER
:检查SET
中是否包含该设备码,若存在则说明已提交,直接返回错误提示,阻止重复提交。SADD
:若设备码不存在,则添加到SET
中,设置一个合理的过期时间来定时清除已提交的记录。