Jedis 与 RedisTemplate 的 Java 实践指南
Jedis 是 Java 生态中直接操作 Redis 的轻量级客户端,而 RedisTemplate 则是 Spring 框架提供的高层抽象。本文将围绕这两种技术路线,展示从环境搭建到典型业务场景的完整实践。
一、工程构建与依赖配置
采用多模块 Maven 工程结构,父工程统筹依赖版本管理,子模块分别承载不同技术方案。
1.1 Jedis 模块依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
1.2 Spring 模块依赖
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.3.2.RELEASE</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
二、Jedis 核心操作
2.1 服务端配置要点
若需远程连接 Redis 服务,需调整配置文件:
- 注释
bind 127.0.0.1行,或修改为指定网卡 - 将
protected-mode设为no - 重启服务使配置生效
2.2 基础数据类型操作
public class JedisBasicTests {
@Test
public void testStringCommands() throws InterruptedException {
Jedis client = new Jedis("192.168.126.129", 6379);
client.set("sessionToken", "xyz789");
client.setex("verifyCode", 120, "8823");
client.set("counter", "10");
client.incr("counter");
client.incrBy("counter", 5);
String token = client.get("sessionToken");
Long ttl = client.ttl("verifyCode");
System.out.println("Token: " + token);
System.out.println("验证码剩余秒数: " + ttl);
client.close();
}
@Test
public void testHashCommands() {
Jedis client = new Jedis("192.168.126.129", 6379);
client.hset("employee:1001", "name", "Alice");
client.hset("employee:1001", "department", "Engineering");
client.hset("employee:1001", "level", "P6");
Map<String, String> profile = client.hgetAll("employee:1001");
System.out.println(profile);
client.close();
}
@Test
public void testListCommands() {
Jedis client = new Jedis("192.168.126.129", 6379);
client.rpush("taskQueue", "task-A", "task-B", "task-C");
client.lpush("taskQueue", "urgent-task");
List<String> tasks = client.lrange("taskQueue", 0, -1);
String nextTask = client.lpop("taskQueue");
System.out.println("队列内容: " + tasks);
System.out.println("取出任务: " + nextTask);
client.close();
}
}
2.3 JSON 对象序列化处理
@Test
public void testJsonSerialization() {
Jedis conn = new Jedis("192.168.126.129", 6379);
Map<String, Object> commodity = new HashMap<>();
commodity.put("sku", "SKU-2024-008");
commodity.put("itemName", "无线降噪耳机");
commodity.put("price", 899.00);
Gson gson = new Gson();
String payload = gson.toJson(commodity);
conn.set("product:detail", payload);
String retrieved = conn.get("product:detail");
Map<?, ?> result = gson.fromJson(retrieved, Map.class);
System.out.println("反序列化结果: " + result);
conn.close();
}
三、典型业务场景实现
3.1 分布式唯一 ID 生成
public class DistributedIdWorker {
private static final String REDIS_HOST = "192.168.126.129";
private static final int REDIS_PORT = 6379;
private static final String COUNTER_KEY = "global:sequence";
public static long fetchNextId() {
try (Jedis jedis = new Jedis(REDIS_HOST, REDIS_PORT)) {
return jedis.incr(COUNTER_KEY);
}
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(() ->
System.out.println(Thread.currentThread().getName()
+ " 获取 ID: " + fetchNextId())
).start();
}
}
}
3.2 基于 Token 的会话管理
public class TokenAuthService {
private static final String HOST = "192.168.126.129";
private static final int PORT = 6379;
private static final int SESSION_TTL = 3600;
public String performLogin(String account, String credential) {
if (!validateCredentials(account, credential)) {
throw new SecurityException("认证信息无效");
}
try (Jedis conn = new Jedis(HOST, PORT)) {
String sessionToken = UUID.randomUUID().toString().replace("-", "");
conn.setex("session:" + sessionToken, SESSION_TTL, account);
return sessionToken;
}
}
public String accessResource(String token) {
if (token == null || token.trim().isEmpty()) {
throw new IllegalArgumentException("缺少有效凭证");
}
try (Jedis conn = new Jedis(HOST, PORT)) {
String account = conn.get("session:" + token);
if (account == null) {
throw new RuntimeException("会话已过期,请重新登录");
}
return "用户 " + account + " 的资源数据";
}
}
private boolean validateCredentials(String account, String credential) {
return "admin".equals(account) && "Secure#123".equals(credential);
}
}
3.3 投票去重系统
public class VoteService {
private static final String SERVER = "192.168.126.128";
private static final int SERVER_PORT = 6379;
public boolean hasParticipated(String eventId, String participantId) {
try (Jedis conn = new Jedis(SERVER, SERVER_PORT)) {
return conn.sismember("vote:" + eventId, participantId);
}
}
public void castVote(String eventId, String participantId) {
if (hasParticipated(eventId, participantId)) {
System.out.println("该用户已投过票");
return;
}
try (Jedis conn = new Jedis(SERVER, SERVER_PORT)) {
conn.sadd("vote:" + eventId, participantId);
}
}
public long tallyVotes(String eventId) {
try (Jedis conn = new Jedis(SERVER, SERVER_PORT)) {
return conn.scard("vote:" + eventId);
}
}
public Set<String> listParticipants(String eventId) {
try (Jedis conn = new Jedis(SERVER, SERVER_PORT)) {
return conn.smembers("vote:" + eventId);
}
}
}
3.4 购物车数据维护
public class ShoppingCartDao {
private static final String HOST_ADDR = "192.168.126.128";
private static final int HOST_PORT = 6379;
private static final String CART_PREFIX = "cart:";
public void addItem(String buyerId, String merchandiseId, int quantity) {
try (Jedis conn = new Jedis(HOST_ADDR, HOST_PORT)) {
conn.hincrBy(CART_PREFIX + buyerId, merchandiseId, quantity);
}
}
public Map<String, String> retrieveCart(String buyerId) {
try (Jedis conn = new Jedis(HOST_ADDR, HOST_PORT)) {
return conn.hgetAll(CART_PREFIX + buyerId);
}
}
public void removeItem(String buyerId, String merchandiseId) {
try (Jedis conn = new Jedis(HOST_ADDR, HOST_PORT)) {
conn.hdel(CART_PREFIX + buyerId, merchandiseId);
}
}
public void clearCart(String buyerId) {
try (Jedis conn = new Jedis(HOST_ADDR, HOST_PORT)) {
conn.del(CART_PREFIX + buyerId);
}
}
}
3.5 秒杀请求队列
public class FlashSaleQueue {
private static final String QUEUE_NAME = "flashsale:requests";
public void enqueueRequest(String requestData) {
try (Jedis conn = new Jedis("192.168.126.129", 6379)) {
conn.lpush(QUEUE_NAME, requestData);
}
}
public String dequeueRequest() {
try (Jedis conn = new Jedis("192.168.126.129", 6379)) {
List<String> result = conn.brpop(30, QUEUE_NAME);
return result != null ? result.get(1) : null;
}
}
public static void main(String[] args) {
FlashSaleQueue queue = new FlashSaleQueue();
Thread producer = new Thread(() -> {
int seq = 1;
while (true) {
queue.enqueueRequest("order-" + seq++);
try {
Thread.sleep(800);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
});
Thread consumer = new Thread(() -> {
while (true) {
String request = queue.dequeueRequest();
if (request != null) {
System.out.println("处理请求: " + request);
}
}
});
producer.start();
consumer.start();
}
}
四、连接池优化配置
4.1 连接池基础使用
public class PoolConfigurationTest {
@Test
public void demonstratePoolUsage() {
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(32);
poolConfig.setMaxIdle(10);
poolConfig.setMinIdle(4);
try (JedisPool pool = new JedisPool(poolConfig, "192.168.126.128", 6379)) {
try (Jedis client = pool.getResource()) {
client.set("poolDemo", "connectedViaPool");
System.out.println(client.get("poolDemo"));
}
}
}
}
4.2 封装数据源组件
public class RedisDatasource {
private static final JedisPool connectionPool;
private static final String SERVER_HOST = "192.168.126.129";
private static final int SERVER_PORT = 6379;
static {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(24);
config.setMaxIdle(8);
config.setMaxWaitMillis(3000);
connectionPool = new JedisPool(config, SERVER_HOST, SERVER_PORT);
}
public static Jedis borrowConnection() {
return connectionPool.getResource();
}
public static void returnConnection(Jedis conn) {
if (conn != null) {
conn.close();
}
}
}
五、Spring Data Redis 实践
5.1 配置文件
spring:
redis:
host: 192.168.64.129
port: 6379
lettuce:
pool:
max-active: 16
max-idle: 8
5.2 字符串类型操作
@SpringBootTest
public class StringTemplateTests {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test
void testValueOperations() {
ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
ops.set("config:theme", "dark");
ops.set("config:refresh", "5000", 60, TimeUnit.SECONDS);
ops.increment("stats:pageView");
String theme = ops.get("config:theme");
System.out.println("当前主题: " + theme);
}
}
5.3 哈希结构操作
@Test
void testHashOperations() {
HashOperations<String, Object, Object> ops = stringRedisTemplate.opsForHash();
ops.put("profile:user:10086", "nickname", "Explorer");
ops.put("profile:user:10086", "region", "Shanghai");
ops.put("profile:user:10086", "badges", "3");
Object region = ops.get("profile:user:10086", "region");
List<Object> allValues = ops.values("profile:user:10086");
System.out.println("地区: " + region);
System.out.println("完整信息: " + allValues);
}
5.4 JSON 数据交互
@Test
void testJsonExchange() throws JsonProcessingException {
ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> article = new HashMap<>();
article.put("articleId", "A-2024-001");
article.put("headline", "Redis 高性能实践");
article.put("viewCount", 15200);
String jsonPayload = mapper.writeValueAsString(article);
ops.set("article:content", jsonPayload);
String stored = ops.get("article:content");
Map<?, ?> parsed = mapper.readValue(stored, Map.class);
System.out.println("解析结果: " + parsed);
}