Java项目中集成Redis提升系统的性能

news2025/2/25 8:03:09

概述

安装Redis

安装

启动Rocky Linux 9.0,在浏览器中打开web console.

如果没有安装Web console,按以下步骤安装启用:
安装命令:
# dnf install cockpit
启用并运行服务
# systemctl enable --now cockpit.socket
开通防火墙:
# firewall-cmd --add-service=cockpit --permanent
# firewall-cmd --reload
rocky的软件仓库里自带了redis,直接yum安装就可以了。点击Web console左边菜单中的终端或Terminal,进入控制台模式。
控制台
然后敲入命令:
# dnf install redis -y
安装完成后,启用服务:
# systemctl enable --now redis
测试安装结果:
# redis-cli ping
如果返回PONG,说明安装成功。

配置

允许外部访问

用vi打开配置文件:
# vi /etc/redis/redis.conf
修改ip4绑定地址为任意,即0.0.0.0
监听地址
按Esc,输入:wq退出。重启Redis:
# systemctl restart redis
添加防火墙:
# firewall-cmd --add-port 6379/tcp --permanent
# firewall-cmd --reload
验证一下安装,找另外一台机器,打开命令行输入:
telnet 192.168.0.128 6379
如果屏幕被清空,说明连接成功,输入quit退出。

写个程序测试一下是否配置成功。

SpringBoot里的spring-boot-starter-data-redis里使用的是lettuce客户端,所以我们这里也用这个。

<dependency>
    <groupId>io.lettuce</groupId>
    <artifactId>lettuce-core</artifactId>
    <version>6.2.1.RELEASE</version>
</dependency>

写段测试代码:

package redis;

import java.time.LocalDateTime;

import io.lettuce.core.RedisClient;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;

public class DemoMain {

	public static void main(String[] args) {
		RedisClient redisClient = RedisClient.create("redis://192.168.0.128:6379/0");
		
		StatefulRedisConnection<String, String> connection = redisClient.connect();
		RedisCommands<String, String> syncCommands = connection.sync();
		syncCommands.set("key", "Hello, Redis!"+LocalDateTime.now());
		connection.close();
		redisClient.shutdown();
		System.out.println("ok!");

	}

}

进入服务器查下结果:

redis-cli get key
“Hello, Redis!2022-12-01T11:44:55.654705500”

限制访问

为了不让别的应用随便接入redis,我们可以修改redis.conf加上访问密码,找到这一行改成这样:
增加密码验证
保存后重启redis服务。此时运行上边的程序,发现报错,错误提示:

NOAUTH HELLO must be called with the client already authenticated,
otherwise the HELLO AUTH <user> <pass> option can be used to
authenticate the client and select the RESP protocol version at the
same time

大概意思就是没发起验证命令。然后我们修改一下,先加入错误的密码:

package redis;

import java.time.LocalDateTime;

import io.lettuce.core.RedisClient;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;

public class DemoMain {

	public static void main(String[] args) {
		RedisClient redisClient = RedisClient.create("redis://111111@192.168.0.128:6379/0");
		
		StatefulRedisConnection<String, String> connection = redisClient.connect();
		RedisCommands<String, String> syncCommands = connection.sync();
		syncCommands.set("key", "Hello, Redis!"+LocalDateTime.now());
		connection.close();
		redisClient.shutdown();
		System.out.println("ok!");

	}

}

运行程序后提示无效的用户名密码:

WRONGPASS invalid username-password pair or user is disabled.

换成正确的密码后,程序正常执行。

启用加密传输

  1. 生成证书
    生成密钥:

openssl genrsa -out server.key 4096

生成证书请求文件:
注意,证书需要配合域名使用。

openssl req -new -key server.key -out server.csr

生成CA证书:

openssl x509 -req -in server.csr -out server.crt -signkey server.key -days 3650

  1. 服务端配置
    端口:

port 0
tls-port 6379

关闭客户端证书验证

tls-auth-clients no

指定证书路径:

tls-cert-file /etc/redis/server.crt
tls-key-file /etc/redis/server.key
tls-ca-cert-file /etc/redis/server.crt

  1. 客户端导入证书

keytool -import -alias demo -file server.crt -keystore E:\openjdk\jdk-17\lib\security\cacerts -storepass changeit

  1. 修改代码
package redis;

import java.io.File;
import java.net.URL;
import java.time.LocalDateTime;

import io.lettuce.core.ClientOptions;
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.SslOptions;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;

public class DemoMain {

	public static void main(String[] args) throws Throwable {
		RedisURI redisUri = RedisURI.Builder.redis("demo.com", 6379).withDatabase(0)
                .withSsl(true).withPassword("123456")
                .withVerifyPeer(false)
                .build();
		RedisClient redisClient = RedisClient.create(redisUri);
		SslOptions sslOptions = SslOptions.builder()
		        .jdkSslProvider()
		        .protocols("TLSv1.2")
		        .truststore(new File("E:\\openjdk\\jdk-17\\lib\\security\\cacerts"), "changeit")
		        .build();
		ClientOptions clientOptions = ClientOptions.builder().sslOptions(sslOptions).build();
		redisClient.setOptions(clientOptions);
		
		StatefulRedisConnection<String, String> connection = redisClient.connect();
		RedisCommands<String, String> syncCommands = connection.sync();
		syncCommands.set("key", "Hello, Redis!" + LocalDateTime.now());
		connection.close();
		redisClient.shutdown();
		System.out.println("ok!");

	}

}

项目实战

创建Springboot项目

先用IDE生成Maven项目,再往pom.xml里加入springboot的相关依赖。pom.xml内容如下:

<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>java-demo</groupId>
		<artifactId>root</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>
	<artifactId>redis-practice</artifactId>
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<maven.compiler.source>17</maven.compiler.source>
		<maven.compiler.target>17</maven.compiler.target>
		<lombok.version>1.18.24</lombok.version>
		<spring-boot.version>2.7.4</spring-boot.version>
	</properties>
	<dependencyManagement>
		<dependencies>

			<dependency>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-dependencies</artifactId>
				<version>${spring-boot.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
			<dependency>
				<groupId>org.projectlombok</groupId>
				<artifactId>lombok</artifactId>
				<version>${lombok.version}</version>
				<scope>provided</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-configuration-processor</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
			<exclusions>
				<exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-tomcat</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-undertow</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>
		<dependency>
			<groupId>org.postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<scope>runtime</scope>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<version>${spring-boot.version}</version>
				<configuration>
					<executable>true</executable>
				</configuration>
				<executions>
					<execution>
						<goals>
							<goal>repackage</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>

配置redis

为了使用密码验证及启用加密传输,我们要自定义 Lettuce的配置类:

package demo;

import java.io.File;
import java.time.Duration;
import java.util.Optional;

import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;

import io.lettuce.core.ClientOptions;
import io.lettuce.core.ReadFrom;
import io.lettuce.core.SslOptions;
import io.lettuce.core.resource.ClientResources;

public class LettuceSslClientConfiguration implements LettuceClientConfiguration {

	@Override
	public boolean isUseSsl() {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	public boolean isVerifyPeer() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean isStartTls() {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public Optional<ClientResources> getClientResources() {
		// TODO Auto-generated method stub
		return Optional.empty();
	}

	@Override
	public Optional<ClientOptions> getClientOptions() {
		SslOptions sslOptions = SslOptions.builder()
		        .jdkSslProvider()
		        .protocols("TLSv1.2")
		        .truststore(new File("E:\\openjdk\\jdk-17\\lib\\security\\cacerts"), "changeit")
		        .build();
		ClientOptions clientOptions = ClientOptions.builder().sslOptions(sslOptions).build();
		return Optional.of(clientOptions);
	}

	@Override
	public Optional<String> getClientName() {
		// TODO Auto-generated method stub
		return Optional.empty();
	}

	@Override
	public Optional<ReadFrom> getReadFrom() {
		// TODO Auto-generated method stub
		return Optional.empty();
	}

	@Override
	public Duration getCommandTimeout() {
		// TODO Auto-generated method stub
		return Duration.ZERO;
	}

	@Override
	public Duration getShutdownTimeout() {
		// TODO Auto-generated method stub
		return Duration.ZERO;
	}

	@Override
	public Duration getShutdownQuietPeriod() {
		// TODO Auto-generated method stub
		return Duration.ZERO;
	}

}

然后配置实例Lettuce客户端实例:

package demo;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;

@Configuration
class AppConfig {

	@Bean
	public LettuceConnectionFactory redisConnectionFactory() {
		var conf = new RedisStandaloneConfiguration("demo.com", 6379);
		conf.setDatabase(0);
		conf.setPassword("123456");
		return new LettuceConnectionFactory(conf, new LettuceSslClientConfiguration());
	}

	@Bean
	StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {

		StringRedisTemplate template = new StringRedisTemplate();
		template.setConnectionFactory(redisConnectionFactory);
		return template;
	}
}

编写测试代码:

package demo;

import java.io.IOException;
import java.util.UUID;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.fasterxml.jackson.databind.ObjectMapper;

@RestController
@RequestMapping("/api/stat")
public class StatisticsController {
	@Autowired
	private JdbcTemplate jdbcTemplate;

	@Autowired
	private StringRedisTemplate redisTemplate;

	@GetMapping("{productId}")
	public ProductStat salesStat(@PathVariable UUID productId) throws IOException {
		ProductStat result = new ProductStat();
		var jsonStr = redisTemplate.opsForValue().get("product:" + productId);
		ObjectMapper mapper = new ObjectMapper();
		//从缓存中获取统计数据,如果没则云数据库中查询。
		if (jsonStr != null) {
			result = mapper.createParser(jsonStr).readValueAs(ProductStat.class);
		} else {
			int rowCount = this.jdbcTemplate.queryForObject("select count(*) from sale_order_item where product_id=?",
					Integer.class, productId);
			result.setSaleCount(rowCount);
			rowCount = this.jdbcTemplate.queryForObject("select count(*) from product_comment where product_id=?",
					Integer.class, productId);
			result.setCommentCount(rowCount);

			redisTemplate.opsForValue().set("product:" + productId, mapper.writeValueAsString(result));
		}
		return result;
	}
}

Postman验证

在这里插入图片描述

总结

Redis本身概念不是很难,就是将一些数据放在内存中,这样可以避开一些耗时的磁盘IO操作,以提升应用程序的性能。其难点在于安装配置,以及框架集成。如果用的Linux,安装过程中涉及操作系统的一些基础命令,如果命令不熟的话,会造成一定的困扰。如果配置加密传输的话,对于证书操作不理解,也会提升安装的难度。同样,框架集成这块,像Springboot这种框架是做了高度封装的,隐藏了很多细节,如果对框架低层不熟的话,也会加高使用的难度。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/76104.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Xinlei cheng报告学习

上面是 下面是momuten encoder 关键词 variance 方差 asymmetric不对称 momentum encoder 动量 dimension维度 convergence收敛 symmetrizationsy均衡 contrastive learning 对比学习 autoregressive自回归 distillation蒸馏 没有 fc layer +bn 裁剪后variance方差变大 cum…

canvas截取多个视频的第一帧,第n秒画面

业务涉及视频预览&#xff0c;不点击视频则不播放而是先展示视频的画面给到用户 “因为本人特别喜欢梅艳芳&#xff0c;所以也留存了很多她的视频&#xff0c;这里就以她的视频做测试了” 截取多个视频的第一帧&#xff0c;使用&#xff1a;Promiseloadeddata事件canvas Pro…

如何提高测试的质量

一、需求与测试需求方面 1.应从产品人员手中获取需求&#xff0c;尽量要求产品人员对需求进行讲解(需求评审) 2.我们要做测试需求分析&#xff0c;并应用相对应的方法论&#xff0c;还要进行需求串讲 3.测试需求分析的方法&#xff1a;分解功能点&#xff0c;然后对每一个功…

数据分析思维(二)|相关思维

1、概念 相关思维是数据分析中最常见的思维之一&#xff0c;在我们观察指标变化的时候&#xff0c;往往需要观察指标之间的相关关系&#xff0c;比如观察自己身高和体重的变化&#xff0c;这就是一种相关思维的体现。 衡量指标之间的相关关系&#xff0c;常见的相关性分析方法…

[Linux打怪升级之路]-重定向

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注支持博主。如果发现有问题的地方欢迎❀大家在评论区指正。 目录 一、文件描述符 1、初…

步步详解IntelliJ IDEA创建springboot项目并运行

1. SpringBoot 简介 SpringBoot 是由 Pivotal 团队提供的全新框架&#xff0c;其设计目的是用来简化 Spring 应用的初始搭建以及开发过程。 我们在学习 Spring 的时候说过 Spring 框架是为了简化开发的&#xff0c;而 SpringBoot 是为了简化 Spring 开发的&#xff0c; 由此…

easylabel | 完美拯救手残党不会标注突出重点!(Label!~ Label!~)

1写在前面 我们在画图的时候经常需要标记某个值, 如散点图中的某个具体的点, 火山图中的某个基因, 但对于代码不太熟悉的小白来说, 还是有一定难度的.&#x1f92a; 本期和大家介绍一个基于shiny轻松进行label的包, 即easylabel包, 轻松实现交互式label, 麻麻再也不用担心你的画…

全国青少年软件编程(Scratch)等级考试二级考试真题2021年12月——持续更新.....

电子学会202112Scratc二级真题及参考答案 1.舞台上有3个角色,小猫的程序如下图所示,另外两个角色没有程序。点击绿旗,下列选项正确的是? A.小猫随鼠标移动,可能会遮挡其他两个角色 B.小猫随鼠标移动,可能会被其他两个角色遮挡 C.小猫不会随鼠标移动,更不会被遮挡 D.…

一睹风采,见证郁锦香酒店遍布全球核心城市的百变姿态

随着消费需求的不断升级&#xff0c;酒店消费场景也进行着多元化的发展&#xff0c;城市高端度假品牌正积极溯源消费需求&#xff0c;寻得品牌文化延伸的可靠路径。同时&#xff0c;各大酒店品牌也加快在市场布局的脚步&#xff0c;希望通过布局城市核心区域获得可持续发展的更…

企业微信-自建应用二:消息发送测试

1.开发过程 要测试企微自建应用的消息发送功能 企业微信开发者中心-调试工具 建立连接 corpsecret即是自建应用的Secret 输入参数&#xff0c;调用接口&#xff0c;即可拿到返回的token 发送应用消息 填写token&#xff0c;以及body消息体 {"touser": "Us…

Birdboot第二天

目录 V4 HttpServletRequest保存请求内容 1.此类专门处理请求 把获取请求的readline()和拆分代码移动过来 2.ClientHandler客户端处理器实例化HttpServletRequest 3. 拆分的信息从局部变量 变成属性 4.建方法 解析请求行 消息头 消息正文 V5 发送响应 1.在客户端处理器 …

非洲秃鹫优化算法:求解全局优化问题的一种新的自然启发元启发式算法(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 元启发式在解决优化问题中起着至关重要的作用。大多数此类算法的灵感来自于自然界中生物的集体智能和觅食。本文以非洲秃鹫的生…

YOLOv4:目标检测的最佳速度和精度

来源&#xff1a;投稿 作者&#xff1a;王同学 编辑&#xff1a;学姐 《YOLOv4&#xff1a;Optimal Speed and Accuracy of Object Detection》 发表时间及作者&#xff1a;2020 CVPR 目录 1.YOLOv4介绍 2.YOLOv4网络结构 2.1 Backbone改进 2.2 Neck改进 3.YOLOv4训练策…

java多线程基础

java多线程基础1. 线程是什么2. 线程的创建和运行方式1&#xff1a;继承Thread类示例:方式2&#xff1a;实现Runnable接口(推荐)示例:3. Thread类的常用方法4. 线程插队&#xff08;1&#xff09;yield 当前线程把时间片让给其它线程&#xff0c;不一定成功示例:&#xff08;2&…

数据库基础-Mongodb数据库复制操作

Mongodb数据库复制操作 关闭mongodb的服务,如下图 创建以下文件夹 现在我们开启三个服务,端口号为9927做为主节点,9928做为从节点,9929做为仲裁节点 仲裁节点的作用是协调leader选举&#xff0c;监测系统运行状态&#xff0c;提供节点互相通讯的数据信息。 开启主服务: m…

【视觉高级篇】24 # 如何模拟光照让3D场景更逼真?(下)

说明 【跟月影学可视化】学习笔记。 什么是镜面反射&#xff1f; 如果若干平行光照射在表面光滑的物体上&#xff0c;反射出来的光依然平行&#xff0c;这种反射就是镜面反射。越光滑的材质&#xff0c;它的镜面反射效果也就越强&#xff0c;并且物体表面会有闪耀的光斑&…

Windows系统下HTTP(S)透明代理

本文为joshua317原创文章,转载请注明&#xff1a;转载自joshua317博客 Windows系统下HTTP(S)透明代理 - joshua317的博客 软件文档地址:goproxy/README_ZH.md at master snail007/goproxy GitHub 一、windows系统下进行下载及安装 分别有两个版本&#xff1a;proxy-admin …

Servlet学习笔记

1.在pom.xml中添加依赖 <dependencies><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><!-- 不会最终打包到服务器中去 --><scope>provided&…

SpringBoot内置tomcat启动过程及原理

作者&#xff1a;李岩科 1 背景 SpringBoot 是一个框架&#xff0c;一种全新的编程规范&#xff0c;他的产生简化了框架的使用&#xff0c;同时也提供了很多便捷的功能&#xff0c;比如内置 tomcat 就是其中一项&#xff0c;他让我们省去了搭建 tomcat 容器&#xff0c;生成 …

和年薪30W的阿里测试员聊过后,才知道自己一直在打杂...

前几天和一个朋友聊面试&#xff0c;他说上个月同时拿到了腾讯和阿里的offer&#xff0c;最后选择了阿里。 阿里内部将员工一共分为了14个等级&#xff0c;P6是资深工程师&#xff0c;P7是技术专家。 其中P6和P7就是一个分水岭了&#xff0c;P6是最接近P7的不持股员工&#x…