redis.conf
配置文件,改完后确保生效,记得重启shutdown
默认daemonize no
改为 daemonize yes
默认protected-mode yes
改为 protected-mode no
默认bind 127.0.0.1
改为 直接注释掉(默认bind 127.0.0.1
只能本机访问)或改成本机IP地址,否则影响远程IP连接
添加redis密码 改为 requirepass 你自己设置的密码
systemctl start firewalld
systemctl stop firewalld
systemctl status firewalld
systemctl disable firewalld
systemctl enable firewalld
firewall-cmd --zone=public --add-port=80/tcp --permanent
--permanent
永久生效,没有此参数重启后失效)firewall-cmd --reload
firewall-cmd --zone= public --query-port=80/tcp
firewall-cmd --zone= public --remove-port=80/tcp --permanent
Jedis Client 是Redis 官网推荐的一个面向 Java 客户端,库文件实现了对各类API进行封装调用
建Module redis_7_study
改POM
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.atguigu.redis7groupId>
<artifactId>redis7_studyartifactId>
<version>1.0-SNAPSHOTversion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.6.10version>
<relativePath/>
parent>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<maven.compiler.source>1.8maven.compiler.source>
<maven.compiler.target>1.8maven.compiler.target>
<junit.version>4.12junit.version>
<log4j.version>1.2.17log4j.version>
<lombok.version>1.16.18lombok.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>redis.clientsgroupId>
<artifactId>jedisartifactId>
<version>4.3.1version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>${junit.version}version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>${log4j.version}version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>${lombok.version}version>
<optional>trueoptional>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
写YML
server.port=7777
spring.application.name=redis7_study
主启动
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Redis7Study01Application {
public static void main(String[] args) {
SpringApplication.run(Redis7Study01Application.class, args);
}
}
业务类
package org.example.demo;
import redis.clients.jedis.Jedis;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class JedisDemo {
public static void main(String[] args) {
// 1 connection 连接,通过指定ip和端口号
Jedis jedis = new Jedis("192.168.64.130", 6379);
// 2 指定访问服务器密码
jedis.auth("123456");
// 3 获得了Jedis客户端,可以像jdbc一样访问redis
System.out.println(jedis.ping());
System.out.println("==============key===============");
// keys
Set<String> keys = jedis.keys("*");
System.out.println(keys);
System.out.println("==============string===============");
// string
jedis.set("k3","hello-jedis");
System.out.println(jedis.get("k3"));
System.out.println(jedis.ttl("k3"));
System.out.println("==============list===============");
// list
jedis.lpush("list","11","22","33");
List<String> list = jedis.lrange("list", 0, -1);
for (String s : list) {
System.out.println(s);
}
System.out.println(jedis.rpop("list"));
System.out.println(jedis.lpop("list"));
System.out.println("==============hash===============");
// hash
jedis.hset("hset1","k1","v1");
Map<String,String> hash = new HashMap<>();
hash.put("k1","1");
hash.put("k2","2");
hash.put("k3","3");
jedis.hmset("hset2",hash);
System.out.println(jedis.hmget("hset2","k1","k3","k2"));
System.out.println(jedis.hget("hset1", "k1"));
System.out.println(jedis.hexists("hset2","k2"));
System.out.println(jedis.hkeys("hset2"));
System.out.println("==============set===============");
// set
jedis.sadd("set1","1","2","3");
jedis.sadd("set2","4");
System.out.println(jedis.smembers("set1"));
System.out.println(jedis.scard("set1"));
System.out.println(jedis.spop("set1"));
jedis.smove("set1","set2","1");
System.out.println(jedis.smembers("set1"));
System.out.println(jedis.smembers("set2"));
System.out.println(jedis.sinter("set1", "set2")); // 交集
System.out.println(jedis.sunion("set1","set2")); // 并集
System.out.println("==============zset===============");
// zset
jedis.zadd("zset1",100,"v1");
jedis.zadd("zset1",80,"v2");
jedis.zadd("zset1",60,"v3");
List<String> zset1 = jedis.zrange("zset1", 0, -1);
for (String s : zset1) {
System.out.println(s);
}
System.out.println();
List<String> zset11 = jedis.zrevrange("zset1", 0, -1);
for (String s : zset11) {
System.out.println(s);
}
}
}
运行!
PONG
==============key===============
[]
==============string===============
hello-jedis
-1
==============list===============
33
22
11
11
33
==============hash===============
[1, 3, 2]
v1
true
[k1, k2, k3]
==============set===============
[1, 2, 3]
3
3
[2]
[1, 4]
[]
[1, 2, 4]
==============zset===============
v3
v2
v1
v1
v2
v3
Process finished with exit code 0
Jedis和Lettuce的区别
jedis和Lettuce都是Redis的客户端,它们都可以连接Redis服务器,但是在SpringBoot2.0之后默认都是使用的Lettuce这个客户端连接Redis服务器。因为当使用Jedis客户端连接Redis服务器的时候,每个线程都要拿自己创建的Jedis实例去连接Redis客户端,当有很多个线程的时候,不仅开销大需要反复的创建关闭一个Redis连接, 而且也是线程不安全的,一个线程通过Jedis实例更改Redis服务器中的数据之后会影响另一个线程;但是如果使用Letuce这个客户端连接Redis服务器的时候,就不会出现上面的情况,Lettuce底层使用的是Netty,当有多个线程都需要连接Redis服务器的时候,可以保证只创建一个Lettuce连接, 使所有的线程共享这一个Lettuce连接, 这样可以减少创建关闭一个L etuce连接时候的开销;而且这种方式也是线程安全的,不会出现一个线程通过 ettuce更改Redis服务器中的数据之后而影响另一个线程的情况;
改POM(导包)
<dependency>
<groupId>io.lettucegroupId>
<artifactId>lettuce-coreartifactId>
<version>6.2.1.RELEASEversion>
dependency>
业务类
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;
import java.util.List;
public class LettuceDemo {
public static void main(String[] args) {
// 1 使用构建器链式编程来builder我们的RedisURI
RedisURI uri = RedisURI.builder()
.withHost("192.168.238.111")
.withPort(6379)
.withAuthentication("default", "123456")
.build();
// 2 连接客户端
RedisClient redisClient = RedisClient.create(uri);
StatefulRedisConnection<String, String> conn = redisClient.connect();
// 3 创建操作的command, 通过conn 创建
RedisCommands<String, String> commands = conn.sync();
// string
commands.set("k1","v1");
System.out.println("==========================="+commands.get("k1"));
System.out.println("==========================="+commands.mget("k1","k2"));
List<String> keys = commands.keys("*");
for (String key : keys) {
System.out.println("========================="+key);
}
// list
commands.lpush("list01","1","2","3");
List<String> list01 = commands.lrange("list01", 0, -1);
for (String s : list01) {
System.out.println("================"+s);
}
System.out.println("===================="+ commands.rpop("list01", 2));
// hash
commands.hset("hash","k1","v1");
commands.hset("hash","k2","v2");
commands.hset("hash","k3","v3");
System.out.println("======================="+commands.hgetall("hash"));
Boolean hexists = commands.hexists("hash", "v2");
System.out.println("------"+hexists);
// set
commands.sadd("s1","1","2");
System.out.println("=================================" + commands.smembers("s1"));
System.out.println(commands.sismember("s1", "1"));
System.out.println(commands.scard("s1"));
// zset
commands.zadd("a1",100,"v1");
commands.zadd("a1",80,"v2");
System.out.println(commands.zrange("a1", 0, -1));
System.out.println("======================"+commands.zcount("a1", "90", "100"));
// 4 各种关闭释放资源 先开后关
conn.close();
redisClient.shutdown();
}
}
PS:这个东西的输出真的很难找到
ps:Module还是刚刚的,所以省略了建Module
改POM(导包)
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-pool2artifactId>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version>2.9.2version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger-uiartifactId>
<version>2.9.2version>
dependency>
写YML
server.port=7777
spring.application.name=redis7_study
# ========================logging=====================
logging.level.root=info
logging.level.com.atguigu.redis7=info
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger- %msg%n
logging.file.name=D:/mylogs2023/redis7_study.log
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger- %msg%n
# ========================swagger=====================
spring.swagger2.enabled=true
#在springboot2.6.X结合swagger2.9.X会提示documentationPluginsBootstrapper空指针异常,
#原因是在springboot2.6.X中将SpringMVC默认路径匹配策略从AntPathMatcher更改为PathPatternParser,
# 导致出错,解决办法是matching-strategy切换回之前ant_path_matcher
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
# ========================redis单机=====================
spring.redis.database=0
# 修改为自己真实IP
spring.redis.host=192.168.111.185
spring.redis.port=6379
spring.redis.password=111111
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
业务类
配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig
{
/**
* redis序列化的工具配置类,下面这个请一定开启配置
* 127.0.0.1:6379> keys *
* 1) "ord:102" 序列化过
* 2) "\xac\xed\x00\x05t\x00\aord:102" 野生,没有序列化过
* this.redisTemplate.opsForValue(); //提供了操作string类型的所有方法
* this.redisTemplate.opsForList(); // 提供了操作list类型的所有方法
* this.redisTemplate.opsForSet(); //提供了操作set的所有方法
* this.redisTemplate.opsForHash(); //提供了操作hash表的所有方法
* this.redisTemplate.opsForZSet(); //提供了操作zset的所有方法
* @param lettuceConnectionFactory
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory)
{
RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(lettuceConnectionFactory);
//设置key序列化方式string
redisTemplate.setKeySerializer(new StringRedisSerializer());
//设置value的序列化方式json,使用GenericJackson2JsonRedisSerializer替换默认序列化
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Configuration
@EnableSwagger2
public class SwaggerConfig
{
@Value("${spring.swagger2.enabled}")
private Boolean enabled;
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.enable(enabled)
.select()
.apis(RequestHandlerSelectors.basePackage("com.lv")) //你自己的package
.paths(PathSelectors.any())
.build();
}
public ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("springboot利用swagger2构建api接口文档 "+"\t"+ DateTimeFormatter.ofPattern("yyyy-MM-dd").format(LocalDateTime.now()))
.description("springboot+redis整合,有问题给管理员发邮件:[email protected]")
.version("1.0")
.termsOfServiceUrl("https://www.atguigu.com/")
.build();
}
}
service
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
@Service
@Slf4j
public class OrderService {
// RedisTemplate ===> StringRedisTemplate
@Resource
private RedisTemplate redisTemplate;
// private StringRedisTemplate redisTemplate;
public static final String ORDER_KEY = "ord:";
public void addOrder(){
int keyId = ThreadLocalRandom.current().nextInt(1000)+1;
String serialNo = UUID.randomUUID().toString();
String key = ORDER_KEY+keyId;
String value = "京东订单" + serialNo;
redisTemplate.opsForValue().set(key,value);
log.info("============key:{}",key);
log.info("============value:{}",value);
}
public String getOrderId(Integer keyId){
return (String) redisTemplate.opsForValue().get(ORDER_KEY + keyId);
}
}
controller
import com.lv.service.OrderService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@Slf4j
@Api(tags = "订单接口")
public class OrderController {
@Resource
private OrderService orderService;
@ApiOperation("新增订单")
@RequestMapping(value = "/order/add", method = RequestMethod.POST)
public void addOrder(){
orderService.addOrder();
}
@ApiOperation("按照keyId 查询订单")
@RequestMapping(value = "/order/{keyId}", method = RequestMethod.GET)
public String getOrderId(@PathVariable Integer keyId){
return orderService.getOrderId(keyId);
}
}
测试
swagger (http://localhost:7070/swagger-ui.html) 测试接口
如果使用RedisTemplate,推荐序列化用StringRedisSerializer,默认使用的是JdkSerializationRedisSerializer,存入Redis会出现乱码问题,查询非常不方便
启动前面配的集群
改写YML(注意IP和端口)
server.port= 7070
spring.application.name=redis7_study01
# ========================logging=====================
logging.level.root=info
logging.level.com.atguigu.redis7=info
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger- %msg%n
logging.file.name=D:/mylogs2023/redis7_study.log
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger- %msg%n
# ========================swagger=====================
spring.swagger2.enabled=true
#在springboot2.6.X结合swagger2.9.X会提示documentationPluginsBootstrapper空指针异常,
#原因是在springboot2.6.X中将SpringMVC默认路径匹配策略从AntPathMatcher更改为PathPatternParser,
# 导致出错,解决办法是matching-strategy切换回之前ant_path_matcher
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
# ========================redis单机=====================
#spring.redis.database=0
## 修改为自己真实IP
#spring.redis.host=192.168.238.111
#spring.redis.port=6379
#spring.redis.password=123456
#spring.redis.lettuce.pool.max-active=8
#spring.redis.lettuce.pool.max-wait=-1ms
#spring.redis.lettuce.pool.max-idle=8
#spring.redis.lettuce.pool.min-idle=0
spring.redis.password=123456
#获取失败,最大重定向次数
spring.redis.cluster.max-redirects=3
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
spring.redis.cluster.nodes=168.238.111:6381,192.168.238.111:6382,192.168.238.112:6383,192.168.238.112:6384,192.168.238.113:6385,192.168.238.113:6386
让master-6381down机,shutdown
查看集群信息 ,看slave是否上位 Cluster nodes
我们客户端再次读写
原因是因为SpringBoot客户端没有动态感知到RedisCluster的最新集群信息
导致这个的原因是
解决方法:
// 很不推荐,不用了解
@Bean
public DefaultClientResources lettuceClientResources() {
return DefaultClientResources.create();
}
@Bean
public LettuceConnectionFactory lettuceConnectionFactory(RedisProperties redisProperties, ClientResources clientResources) {
ClusterTopologyRefreshOptions topologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
.enablePeriodicRefresh(Duration.ofSeconds(30)) //按照周期刷新拓扑
.enableAllAdaptiveRefreshTriggers() //根据事件刷新拓扑
.build();
ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder()
//redis命令超时时间,超时后才会使用新的拓扑信息重新建立连接
.timeoutOptions(TimeoutOptions.enabled(Duration.ofSeconds(10)))
.topologyRefreshOptions(topologyRefreshOptions)
.build();
LettuceClientConfiguration clientConfiguration = LettuceClientConfiguration.builder()
.clientResources(clientResources)
.clientOptions(clusterClientOptions)
.build();
RedisClusterConfiguration clusterConfig = new RedisClusterConfiguration(redisProperties.getCluster().getNodes());
clusterConfig.setMaxRedirects(redisProperties.getCluster().getMaxRedirects());
clusterConfig.setPassword(RedisPassword.of(redisProperties.getPassword()));
LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(clusterConfig, clientConfiguration);
return lettuceConnectionFactory;
}
刷新节点结群拓扑和动态感应(推荐)
改YML,一步到位(最后多了两行配置)
server.port= 7070
spring.application.name=redis7_study01
# ========================logging=====================
logging.level.root=info
logging.level.com.atguigu.redis7=info
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger- %msg%n
logging.file.name=D:/mylogs2023/redis7_study.log
logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger- %msg%n
# ========================swagger=====================
spring.swagger2.enabled=true
#在springboot2.6.X结合swagger2.9.X会提示documentationPluginsBootstrapper空指针异常,
#原因是在springboot2.6.X中将SpringMVC默认路径匹配策略从AntPathMatcher更改为PathPatternParser,
# 导致出错,解决办法是matching-strategy切换回之前ant_path_matcher
spring.mvc.pathmatch.matching-strategy=ant_path_matcher
# ========================redis单机=====================
#spring.redis.database=0
## 修改为自己真实IP
#spring.redis.host=192.168.238.111
#spring.redis.port=6379
#spring.redis.password=123456
#spring.redis.lettuce.pool.max-active=8
#spring.redis.lettuce.pool.max-wait=-1ms
#spring.redis.lettuce.pool.max-idle=8
#spring.redis.lettuce.pool.min-idle=0
spring.redis.password=123456
#获取失败,最大重定向次数
spring.redis.clusterspring.redis.cluster.nodes=192.1.max-redirects=3
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
68.238.111:6381,192.168.238.111:6382,192.168.238.112:6383,192.168.238.112:6384,192.168.238.113:6385,192.168.238.113:6386
#支持集群拓扑动态感应刷新,自适应拓扑刷新是否使用所有可用的更新,默认false关闭
spring.redis.lettuce.cluster.refresh.adaptive=true
#定时刷新
spring.redis.lettuce.cluster.refresh.period=2000