文章目录
一、使用Jedis连接并操作Redis
1、创建一个springboot项目,导入需要的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
<version>1.4.5.RELEASE</version>
</dependency>
2、使用测试单元测试一下Redis连接
package com.gykalc.testjedis;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import redis.clients.jedis.Jedis;
@SpringBootTest
class TestjedisApplicationTests {
@Test
void contextLoads() {
}
@Test
void testJedis() {
/**
* 使用Jedis连接redis服务器
* 首先要注意:要关闭redis服务器的防火墙
* 关闭防火墙命令:service iptables stop | systemctl stop firewalld.service
* 查看防火墙状态:service iptables status | systemctl status firewalld.service
* 启动防火墙命令:setvice iptables start | systemctl start firewalld.service
* systemctl enable firewalld.service //设置开机自动启动
* systemctl disable firewalld.service //设置关闭开机制动启动
*/
Jedis jedis = new Jedis("192.168.112.102", 6379);
// 连接成功之后就可以操作redis了
// jedis在线文档:https://tool.oschina.net/apidocs/apidoc?api=jedis-2.1.0
jedis.set("country", "china");
jedis.close();
}
}
测试是否成功设置了一个键值对
二、模拟请求缓存
/**
* 模拟用户请求一个商品时,我们使用Jedis缓存
*/
@Test
void userRequest() {
// 假设用户请求一个商品,传来一个商品的id
String itemId = "1358907";
Jedis jedis = new Jedis("192.168.112.102", 6379);
String key = "item_" + itemId;
Map<String, String> itemInfo = null;
// 如果存在这个key,那么我们就从缓存中读取数据
if (jedis.exists(key)) {
itemInfo = jedis.hgetAll(key);
System.out.println("从redis中读取的缓存数据");
}else { // 不存在我们就从数据库读取数据
// 假设数据库读取数据如下
itemInfo = new HashMap<>();
itemInfo.put("id", itemId);
itemInfo.put("name", "华为P40Pro");
itemInfo.put("price", "5999");
// 将从数据库读取的数据存储到redis中
jedis.hmset(key, itemInfo);
System.out.println("从数据库读取的数据,并存入缓存");
}
System.out.println(itemInfo);
jedis.close();
}
三、自定义数据分片计算
当数据需要存储在不同的redis服务上时,需要代码端完成数据分片存储的计算逻辑;模拟海量数据的key-value对,自定义对key值进行计算,完成分布式存储;(6379、6380、6381各自有一部分数据)
package com.gykalc.testjedis;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import redis.clients.jedis.Jedis;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@SpringBootTest
class TestjedisApplicationTests {
private static List<Jedis> JEDISPOOL = new ArrayList<>();
static {
Jedis jedis6379 = new Jedis("192.168.112.102", 6379);
Jedis jedis6380 = new Jedis("192.168.112.102", 6380);
Jedis jedis6381 = new Jedis("192.168.112.102", 6381);
JEDISPOOL.add(jedis6379);
JEDISPOOL.add(jedis6380);
JEDISPOOL.add(jedis6381);
}
@Test
void contextLoads() {
}
@Test
void testJedis() {
/**
* 使用Jedis连接redis服务器
* 首先要注意:要关闭redis服务器的防火墙
* 关闭防火墙命令:service iptables stop | systemctl stop firewalld.service
* 查看防火墙状态:service iptables status | systemctl status firewalld.service
* 启动防火墙命令:setvice iptables start | systemctl start firewalld.service
* systemctl enable firewalld.service //设置开机自动启动
* systemctl disable firewalld.service //设置关闭开机制动启动
*/
Jedis jedis = new Jedis("192.168.112.102", 6379);
// 连接成功之后就可以操作redis了
jedis.set("country", "china");
jedis.close();
}
/**
* 模拟用户请求一个商品时,我们使用Jedis缓存
*/
@Test
void userRequest() {
// 假设用户请求一个商品,传来一个商品的id
String itemId = "1358907";
Jedis jedis = new Jedis("192.168.112.102", 6379);
String key = "item_" + itemId;
Map<String, String> itemInfo = null;
// 如果存在这个key,那么我们就从缓存中读取数据
if (jedis.exists(key)) {
itemInfo = jedis.hgetAll(key);
System.out.println("从redis中读取的缓存数据");
}else { // 不存在我们就从数据库读取数据
// 假设数据库读取数据如下
itemInfo = new HashMap<>();
itemInfo.put("id", itemId);
itemInfo.put("name", "华为P40Pro");
itemInfo.put("price", "5999");
// 将从数据库读取的数据存储到redis中
jedis.hmset(key, itemInfo);
System.out.println("从数据库读取的数据,并存入缓存");
}
System.out.println(itemInfo);
jedis.close();
}
/**
* 自定义数据分片计算
*/
@Test
void autoSharedWrite() {
// 模拟海量数据插入redis
for (int i = 0; i < 1000; i ++) {
String key = "item_1803_cs";
String value = "item_1803_values_";
key += i;
value += i;
int index = hashShared(key);
JEDISPOOL.get(index).set(key, value);
}
}
@Test
void autoSharedRead() {
// 模拟海量数据读取
for (int i = 0; i < 1000; i ++) {
String key = "item_1803_cs";
key += i;
int index = hashShared(key);
String s = JEDISPOOL.get(index).get(key);
System.out.println(s);
}
}
/**
* 使用hash散列取余算法计算出使用哪个redis服务
* 返回0 - jedis连接池中连接数 - 1
* @param key
* @return
*/
public int hashShared(String key) {
int size = getJedisPoolSize();
// 因为hashCode可能为负数,所以我们&上Integer.MAX_VALUE
return (key.hashCode() & Integer.MAX_VALUE) % size;
}
public static int getJedisPoolSize() {
return JEDISPOOL.size();
}
}
四、Jedis本身的数据分片计算
/**
* jedis本身实现了数据分片计算
*/
@Test
void jedisShard() {
List<JedisShardInfo> infoList = new ArrayList<>();
JedisShardInfo info6379 = new JedisShardInfo("192.168.112.102", 6379);
JedisShardInfo info6380 = new JedisShardInfo("192.168.112.102", 6380);
JedisShardInfo info6381 = new JedisShardInfo("192.168.112.102", 6381);
infoList.add(info6379);
infoList.add(info6380);
infoList.add(info6381);
ShardedJedis sJedis = new ShardedJedis(infoList);
sJedis.set("shardedJedis", "hello world shardedJedis");
}
五、Jedis的分片连接池
@Test
void jedisPool() {
// 利用节点信息,配置最大连接数、最小连接数、最大空闲数
// 连接超时、connectTime、socketTime、重连次数等
List<JedisShardInfo> infoList = new ArrayList<>();
JedisShardInfo info6379 = new JedisShardInfo("192.168.112.102", 6379);
JedisShardInfo info6380 = new JedisShardInfo("192.168.112.102", 6380);
JedisShardInfo info6381 = new JedisShardInfo("192.168.112.102", 6381);
infoList.add(info6379);
infoList.add(info6380);
infoList.add(info6381);
// 构造一个具有配置条件的配置对象
GenericObjectPoolConfig config = new JedisPoolConfig();
config.setMaxIdle(8); // 设置最大空闲连接数
config.setMaxTotal(200); // 设置最大连接数
// 利用配置对象和连接信息构造连接池
ShardedJedisPool jedisPool = new ShardedJedisPool(config, infoList);
ShardedJedis resource = jedisPool.getResource();
for (int i = 0; i < 100; i++) {
String key = "item_1803_cs";
String value = "item_1803_values_";
key += i;
value += i;
resource.set(key, value);
}
//可以实现api操作,分布式计算
jedisPool.returnResource(resource);
}
六、springboot整合jedis
1、在application.yaml中进行配置
server:
port: 8080
mycustom:
maxIdle: 8 # redis最大空闲数
maxTotal: 200 # redis最大连接数
redisinfos: # redis信息
- host: 192.168.112.102
port: 6379
- host: 192.168.112.102
port: 6380
- host: 192.168.112.102
port: 6381
2、创建一个配置类,读取yaml中的配置
package com.gykalc.testjedis.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@ConfigurationProperties(prefix = "mycustom")
public class RedisProperties {
private List<RedisInfo> redisInfos;
private Integer maxIdle;
private Integer maxTotal;
public static class RedisInfo {
private String host;
private Integer port;
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
}
public List<RedisInfo> getRedisInfos() {
return redisInfos;
}
public void setRedisInfos(List<RedisInfo> redisInfos) {
this.redisInfos = redisInfos;
}
public Integer getMaxIdle() {
return maxIdle;
}
public void setMaxIdle(Integer maxIdle) {
this.maxIdle = maxIdle;
}
public Integer getMaxTotal() {
return maxTotal;
}
public void setMaxTotal(Integer maxTotal) {
this.maxTotal = maxTotal;
}
}
3、创建一个Redis配置类,注入读取到的类
package com.gykalc.testjedis.config;
import com.gykalc.testjedis.properties.RedisProperties;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.ShardedJedisPool;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class RedisConfig {
/**
* 获取到redis配置类
*/
@Autowired
private RedisProperties redisProperties;
/**
* 使用Bean注解,将连接池对象交给spring进行管理
* Scope注解singleton:单例
* @return
*/
@Bean
@Scope("singleton")
public ShardedJedisPool shardedJedisPool() {
List<JedisShardInfo> infoList = new ArrayList<>();
List<RedisProperties.RedisInfo> redisInfos = redisProperties.getRedisInfos();
for (RedisProperties.RedisInfo info: redisInfos) {
JedisShardInfo jedisShardInfo = new JedisShardInfo(info.getHost(), info.getPort());
infoList.add(jedisShardInfo);
}
// 构造一个具有配置条件的配置对象
GenericObjectPoolConfig config = new JedisPoolConfig();
config.setMaxIdle(redisProperties.getMaxIdle()); // 设置最大空闲连接数
config.setMaxTotal(redisProperties.getMaxTotal()); // 设置最大连接数
// 利用配置对象和连接信息构造连接池
return new ShardedJedisPool(config, infoList);
}
}
4、Controller
package com.gykalc.testjedis.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPool;
@RestController
@RequestMapping("/test")
public class JedisController {
@Autowired
private ShardedJedisPool shardedJedisPool;
@RequestMapping(value = "/getData")
public String getData(String id) {
String key = "shardedJedisPool_" + id;
ShardedJedis resource = shardedJedisPool.getResource();
String result = "";
if (resource.exists(key)) {
System.out.println("从redis缓存中获取数据");
result = resource.get(key);
}else {
System.out.println("从数据库中获取数据");
result = "{id: \"" + id + "\", name: \"gyk\", age: \"24\"}";
// 存入缓存中
resource.set(key, result);
}
// 关闭资源
shardedJedisPool.returnResource(resource);
return result;
}
}