由于springboot在业内的使用占比非常大,所以我们不仅仅要学redis的命令,更多使用的是redis与springboot的整合。那接下来,就一起学习关于springboot整合redis的内容吧。
学习redis,需要类比MySql。使用java连接MySql时,我们使用了JDBC,,同理,连接redis时,我们也需要这样的一个连接代理,因此,出现了Jedis。
但由于Jedis对线程并不安全,于是出现了Lettuce(翻译:生菜),后来,spring为了整合redis,推出了RedisTemplate,当然,这是对lettuce的封装和加强。本次介绍就依次介绍这三个以及它们的使用(重点是RedisTemplate,因为以后大多使用这个作为连接redis的连接器)。
在进行操作之前,大家要确保redis服务是开启的。
redis-cli -a 123321 -p 6379 --raw
-a: redis密码 -p: 端口 --raw: 表示支持中文显示(当redis存入中文不显示乱码)
jedis client是Redis官网推荐的一个面向java客户端,库文件实现了对各类API进行封装调用。
五步法建项目:
(1)建module
这里我们可以选择直接建立springboot项目,然后勾选一个web的start,版本使用2.6.10。
或者建立一个maven项目,后续在pom添加对应的依赖。
如果对建项目不熟,可以先学springboot的教材(推荐黑马程序员的教学)
(2)改pom
因为这是对Jedis的使用,所以需要添加Jedis的依赖,后续为了方便,我们还添加了lombok的依赖以及junit的依赖。
<parent>
<!-- 父项目依赖-->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.10</version>
<relativePath/>
</parent>
<!-- 版本控制-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
</properties>
<dependencies>
<!-- springboot通用模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- jedis依赖-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.3.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>
这里建议直接复制,不容易出错。
(3)写YML
因为使用的Jedis,所以简单配置一下port和application.name。
server:
port: 8080
spring:
application:
name: redis7
(4)主启动类
如果建立项目是使用springboot的话,主启动类会自动生产,如果建立maven的话,建一个自己的包以及主启动类,包结构如下:
config,service,controller,domo包里面没有类,整个结构只有主启动类。
package com.itludehu.redis;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RedisApplication {
public static void main(String[] args) {
SpringApplication.run(RedisApplication.class);
}
}
(5)业务类
最后,我们就可以进行jedis的业务测试了,为了方便,不再新建一个测试类,而是再demo包里面新建一个类RedisDemo:
public class RedisDemo {
//使用原生的jedis来进行连接redis
public static void main(String[] args) {
//1,指定端口,ip获得连接redis的连接
Jedis jedis = new Jedis("192.168.190.128", 6379);
//2,指定访问器的密码
jedis.auth("123321");
//3.获得jedis客户端 和jdbc一样,访问redis
System.out.println(jedis.ping());
//keys的操作
Set<String> keys = jedis.keys("*");
System.out.println(keys);
//string的操作
jedis.set("k3","hello-Jedis7");
//list
jedis.lpush("list","11","22","33");
List<String> list = jedis.lrange("list", 0, -1);
for(String element : list){
System.out.println(element);
}
}
}
可以将主方法运行起来并得到结果。
通过上面,可以得到,使用Jedis步骤:1,new 一个Jedis并连接好ip和端口(这里放入你们自己的ip),并使用方法auth()指定密码。2,使用jedis对redis的命令进行操作,这里的操作值redis的命令,上面仅仅写了几个命令的接口,各位可以参照其他命令的接口并运行起来。
上面的jedis以及可以对redis数据库进行操作了,但是有一个很大的问题,每当业务需要连接redis时候,都需要new一个Jedis,造成线程不安全,,当很多客户端需要连接redis的时候,这样会产生很多对象,浪费内存并且会是服务器宕机。
对比于MySql,解决这样的问题就是使用一个数据源DataSource来解决,所以redis中出现了Lettuce(生菜)。
lettuce是一个redis的Java驱动包。
优势:lettuce底层使用的Netty,当有很多个线程都需要连接redis服务器的时候,可以保证只创建一个lettuce连接,使所有的线程都共享这一个连接,这样减少了很大的开销;并且线程之间是安全的。
因为要使用到Lettuce,那需要在pow中添加对应的依赖
<!-- lettcue的依赖-->
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.2.1.RELEASE</version>
</dependency>
在代码中的demo包中新建一个类LettuceDemo:
public class LettuceDemo {
public static void main(String[] args) {
//1.使用构建器链式编程构建Builder出lettuce
RedisURI url = RedisURI.builder()
.redis("192.168.190.128")
.withPort(6379)
.withAuthentication("default", "123321")
.build();
//2,创建连接客户端
RedisClient redisClient = RedisClient.create(url);
StatefulRedisConnection conn = redisClient.connect();
//3.创建操作的command,使用conn
RedisCommands commands = conn.sync();
//-----------业务逻辑---------------
//key
List keys = commands.keys("*");
System.out.println("***************"+keys);
//String
commands.set("k5","hello-lettuce");
Object k5 = commands.get("k5");
System.out.println("***************"+k5);
//list
//4.各种关闭释放资源
conn.close();;
redisClient.shutdown();
}
}
在进行业务逻辑后,记得关闭相应的资源:conn.close(); redisClient.shutdown();
运行代码也可以得到相应的结果,同样,这里仅仅写了几个命令接口,其他需要自己动手操作。
RedisTemplate是spring整合redis的常用的连接器。
spring优点就是整合其他技术,然后将这些技术放入Ioc的容器中,让spring进行管理,这样大大简化了我们的开发。
使用RedisTemplate,我们要先添加相应的依赖坐标,包括:spring和redis的整合启动坐标,commons-pool2的坐标。
<!-- springboot整合redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
添加好依赖后,就可以修改yml文件中的配置。
server:
port: 8080
spring:
application:
name: redis7
redis:
database: 0
password: 123321
host: 192.168.190.128
port: 6379
lettuce: #连接器
pool:
max-active: 8
max-wait: -1ms
max-idle: 8
min-idle: 0
!!!配置中的连接参数记得修改成你们自己的。
因为redisTemplate是对lettuce的封装加强,所有连接器使用的还是lettoce。
database: 0 表示连接的是redis的第一个库(redis一共有16个库)
password: 密码
host: 主机ip
port: 端口
接下来就是业务类的编写了。
之前添加了web的依赖,就在service和controller包下新建对应的OrderService和OrderController:
代码如下:
Service层
@Service
public class OrderService {
public static final String ORDER_KEY = "order:";
@Resource
private RedisTemplate redisTemplate;
public void addOrder(){
int keyID = ThreadLocalRandom.current().nextInt(1000)+1;
String serialNo = UUID.randomUUID().toString();
String key = ORDER_KEY + keyID;
String value = "京东订单" + serialNo;
//存入redis
redisTemplate.opsForValue().set(key,value);
System.out.println("***Key: "+ key);
System.out.println("***value: {}"+value);
}
public String getOrderById(Integer keyID){
return (String) redisTemplate.opsForValue().get(ORDER_KEY + keyID);
}
}
里面注入了RedisTemplate,并创建了两个方法:addOrder和getOrderByID。
在里面,直接调用redisTemplate.opsForValue.set(key,value)就是对redis进行set key value的命令。
redisTemplate有几种opsFor.*:
opsForValue: 表示对String类型进行操作。
opsForList: 表示对List类型进行操作。
opsForHash:表示对hash类型进行操作。
opsForSet:表示对set进行操作。
opsForZSet:表示对zSet操作。
controller层:
@RestController
public class OrderController {
@Resource
private OrderService orderService;
@GetMapping(value = "/order/add")
public void addOrder(){
orderService.addOrder();
}
@RequestMapping(value = "/order/{keyID}",method = RequestMethod.GET)
public String getOrderByID(@PathVariable Integer keyID){
return orderService.getOrderById(keyID);
}
}
上面定义了两个请求,一个是添加Order,一个是根据ID获取Oder。
启动主程序后,我们打开第一个请求,存入一个Order。
但奇怪的是,获取请求并没有获取到,于是我们去redis数据库进行查询。
输入指令: keys *
可以看到一个很奇怪的东西:
数据库出现了乱码,使用的redisTemplate存入的数据有一个不知道的前缀,根据源码,发现是spring对存入的数据进行了序列化的默认序列化,导致前面出现了乱码,但我们本身不希望有乱码的出现,于是需要我们手动配置一个序列化的工具给redisTemplate。
在config包中新建一个RedisConfig类,并注解配置类@Configuration:
@Configuration
public class RedisConfig {
//解决redis的序列化问题:
@Bean
public RedisTemplate<String,Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory){
RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
//注入lettuce工厂
redisTemplate.setConnectionFactory(lettuceConnectionFactory);
//设置key的序列化方式String
redisTemplate.setKeySerializer(new StringRedisSerializer());
//设置value的序列化方式json,使用GenericJackson2JsonRedisSerializer
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
return redisTemplate;
}
}
这样序列化的方式就解决了。
运行发现后,redis数据没有了前缀。
当然,可以使用另外一种方法,也是就使用RedisTemplate的子类StringRedisTemplate来进行redis的连接,它本身就已经初始化了序列化类,所有在存入数据时并不会产生乱码前缀。
@Resource
private StringRedisTemplate stringRedisTemplate;
至此,springboot整合redis的基础就结束了。
后续会发布关于当使用redisTemplate来对对象(引用类型)进行存储到redis的一些步骤和会出现的问题!