Redis SpringBoot集成Redis-初学篇
Redis 简介
介绍:
关于 Redis ,官网 redis.io 有一段定义:Redis 是一个开源的、基于内存的数据结构存储仓库,被用作数据库、缓存和消息代理。
作为数据库,Redis 是一个速度非常快的非关系数据库(Non-Relational Database),它可以存储键 (Key) 与5种不同类型的值 (Value) 之间的映射 (Mapping) ,可以将存储在内存的键值对数据持久化到硬盘,可以使用复制特性来扩展读性能,还可以使用客户端分片来扩展写性能。
作为缓存中间件,相比 Memcached ,Redis 支持更多的数据结构和更丰富的数据操作,另外 Redis 有着丰富的集群方案和使用场景。
数据类型
Redis 数据类型不仅与关系数据库管理系统 (RDBMS) 不同,也不同于任何简单的 NoSQL 键-值数据存储。Redis 数据类型类似于编程语言的基础数据类型,因此开发人员感觉很自然,每个数据类型都支持适用于其类型的操作,受支持的数据类型包括:
- String (字符串)
- Hash (哈希) .
- List (列表)
- Set (集合)
- Zset (Sorted Set: 有序集合)
优势
Redis 的优势包括它的速度、对富数据类型的支持、操作的原子性,以及通用性:
- 性能极高,它每秒可执行约 100,000 个 Set 以及约100,000 个 Get 操作;
- 丰富的数据类型),Redis 对大多数开发人员己知的大多数数据类型提供了原生支持,这使得各种问题得以轻松解决;
- 原子性,因为所有 Redis 操作都是原子性的,所以多个客户端会并发地访问一个 Redis 服务器,获取相同的更新值;
- 丰富的特性,Redis 是一个多效用工具,有非常多的应用场景,包括缓存、消息队列 (Redis 原生支持发布/订阅)、短期应用程序数据 (比如 Web 会话、Web 页面命中计数) 等。
Redis 基本使用
Windows 安装
下载地址: https://github.com/MSOpenTech/redis/releases
Redis 支持 32 位和 64 位,根据自己的实际情况选择。下载后解压即可
配置
安装后,在不配置Redis的情况下,Redis 也可以直接启动,因为有一个默认配置文件。在官方发布的版本中一般叫做 redis.conf, 而在我们使用的是windows编译的版本,配置文件改为叫做 redis.windows.conf 这个文件中包含了Redis各方面的配置,注意大部分配置行都是英文且以#开头,表示注释,只有不以#开头的行才是生效的配置项。具体配置项大家有兴趣可
以自行补充了解,这里只简单介绍几个配置项:
bind 127.0.0.1: 绑定的主机
port6379: 端口号
requirepass foobared: 请求密码,默认是注释的
save9001、save 30010、save 60 10000: 同步数据文件
启动
打开一个cmd窗口
找到解压后的Redis存放的路径然后 redis-server redis.windows.conf
d:
cd D:\Redis-x64-3.2.100
redis-server redis.windows.conf
如上图界面, 表示服务启动成功(注意,启动后 cmd 窗口不要关闭)
连接
方法1: 在Redis目录里双击打开 redis-cli.exe
没有密码的就已经连接成功了,有密码的则
方法2:打开一个cmd窗口
找到解压后的Redis存放的路径然后
无秘密:redis-cli.exe -h 127.0.0.1 -p 6379
有密码: redis-cli.exe -h 127.0.0.1 -p 6379 -a hxy
基本操作
使用 set,get 命令进行数据的简单写和读:
Jedis 操作 Redis
- 添加 jedis 依赖:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
- 编写 junit 单元测试:
@SpringBootTest
@RunWith(SpringRunner.class)
public class JedisTester {
@Test
public void testString(){
Jedis jedis = new Jedis("127.0.0.1",6379);
jedis.auth("hxy");
//添加--------
jedis.set("name","ouyangwei");
System.out.println(jedis.get("name"));
//拼接--------
jedis.append("name","czkt");
System.out.println(jedis.get("name"));
//删除--------
jedis.del("name");
System.out.println(jedis.get("name"));
//设置多个键值对
jedis.mset("name","lll","age","13","add","cz");
System.out.println(jedis.get("name")+"-"+jedis.get("age")+"-"+jedis.get("add"));
}
}
连接池
在实际使用中,不会再每次使用时都创建 Jedis 对象,一般会使用连接池,并提供一个工具类来对外使用。
使用连接池的好处:效率更高、线程安全
连接池:
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public final class RedisPool {
//Redis服务器IP
private static String ADDR = "192.168.0.100";
//Redis的端口号
private static int PORT = 6379;
//访问密码
private static String AUTH = "foobared";
//可用连接实例的最大数目,默认值为8
//如果赋值为-1,则表示不限制如果pool已经分配了maxActive哥Jedis实例,则此pool的状态为exhausted(耗尽)
private static int MAX_ACTIVE = 1024;
//控制一个pool最多有多少个状态为idle(空闲的)jedis实例,默认值为8
private static int MAX_IDLE = 200;
//等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时,如果等待时间,则直接抛出JedisConnectionException
private static int MAX_WXIT = 1000;
private static int TIMEOUT = 1000;
//在borrow一个jedis实例时,是否提前进行validate操作,如果为true,则得到的jedis实例均是可用的
private static boolean TEST_ON_BORROW = true;
private static JedisPool jedisPool = null;
/**
* 初始化Redis连接池
*/
static {
try {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(MAX_ACTIVE);
config.setMaxIdle(MAX_IDLE);
config.setMaxWaitMillis(MAX_WXIT);
config.setTestOnBorrow(TEST_ON_BORROW);
jedisPool = new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取Jedis实例
*
* @return
*/
public synchronized static Jedis getJedis() {
try {
if (jedisPool != null) {
Jedis resource = jedisPool.getResource();
return resource;
} else {
return null;
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 释放jedis资源
*
* @Param jedis
*/
public static void returnResource(final Jedis jedis) {
if (jedis != null) {
jedisPool.returnResource(jedis);
}
}
}
工具类:
import redis.clients.jedis.Jedis;
public class RedisUtil {
/**
* 设置key的有效期,单位是秒
*
* @param key
* @param exTime
* @return
*/
public static Long expire(String key, int exTime) {
Jedis jedis = null;
Long result = null;
try {
//从Redis连接池获得Jedis对象
jedis = RedisPool.getJedis();
//设置成功则返回Jedis对象
result = jedis.expire(key, exTime);
} catch (Exception e) {
e.printStackTrace();
} finally {
RedisPool.returnResource(jedis);
}
return result;
}
//exTime的单位是秒
//设置key-value并且设置超时时间
public static String setEx(String key, String value, int exTime) {
Jedis jedis = null;
String result = null;
try {
jedis = RedisPool.getJedis();
result = jedis.setex(key, exTime, value);
} catch (Exception e) {
e.printStackTrace();
return result;
} finally {
RedisPool.returnResource(jedis);
}
return result;
}
public static String set(String key,String value) {
Jedis jedis = null;
String result = null;
try {
jedis = RedisPool.getJedis();
result = jedis.get(key,value);
} catch (Exception e) {
e.printStackTrace();
return result;
} finally {
RedisPool.returnResource(jedis);
}
return result;
}
public static String get(String key) {
Jedis jedis = null;
String result = null;
try {
jedis = RedisPool.getJedis();
result = jedis.get(key);
} catch (Exception e) {
e.printStackTrace();
return result;
} finally {
RedisPool.returnResource(jedis);
}
return result;
}
public static Long del(String key) {
Jedis jedis = null;
Long result = null;
try {
jedis = RedisPool.getJedis();
result = jedis.del(key);
} catch (Exception e) {
e.printStackTrace();
return result;
} finally {
RedisPool.returnResource(jedis);
}
return result;
}
}
SpringBoot 操作 Redis
spring-boot-starter-data-redis
Spring Boot 提供了对 Redis 集成的组件包: spring-boot-starter-data-redis,它依赖于 spring-data-redis 和 lettuce。Spring Boot 1.0 默认使用的是 Jedis 客户端,2.0替换成了 Lettuce,但如果你从 Spring Boot 1.5.X 切换过来,几乎感受不大差异,这是因为 spring-boot-starter-data-redis 为我们隔离了其中的差异性。
- Lettuce:是一个可伸缩线程安全的 Redis 客户端,多个线程可以共享同一个
RedisConnection, 它利用优秀 Netty NIO 框架来高效地管理多个连接。 - Spring Data: 是 Spring 框架中的一个主要项目,目的是为了简化构建基于 Spring 框架应用的数据访问,包括非关系数据库、Map-Reduce 框架、云数据服务等,另外也包含对关系数据库的访问支持。
- Spring Data Redis: 是 Spring Data 项目中的一个主要模块,实现了对 Redis 客户端 API 的高度封装,使对 Redis 的操作更加便捷。
因此 Spring Data Redis 和 Lttuce 具备的功能,spring-boot-starter-data-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>
- application.properties 配置相关信息
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=localhost
# Redis 服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=hxy
#连接池最大连接数(使用负值表示没有限制)默认8
spring.redis.lettuce.pool.max-active=8
#连接池最大阳塞等待时间(使用负值表示没有限制)默认-1
spring.redis.lettuce.pool.max-wait=-1
#连接池中的最大空闲连接默认8
spring.redis.lettuce.pool.max-idle=8
#连接池中的最小空闲连接默认日
spring.redis.lettuce.pool.min-idle=0
- 测试使用
在单元测试中,注入 StringRedisTemplate 和 RedisTemplate
@SpringBootTest
@RunWith(SpringRunner.class)
public class Ch08ApplicationTests {
@Resource
private StringRedisTemplate stringRedisTemplate; //操作字符串数据
@Resource
private RedisTemplate redisTemplate; //操作其他数据类型
@Test
public void testString() {//操作字符串
//--1--
//多次进行 set 相同的 key, 健对应的值会被覆盖
stringRedisTemplate.opsForValue().set("name","zxcv");
//--2--
ValueOperations op = stringRedisTemplate.opsForValue();
op.set("01","xiaomin");
//表示60秒后过期
op.set("02","xiaohong",60, TimeUnit.SECONDS);
}
@Test
public void testObj(){//操作实体类
User user = new User("xiaomin","123456",1,null);
ValueOperations<String,User> operations=redisTemplate.opsForValue();
operations.set("demo.crm.user.czkt",user);
User u=operations.get("demo.crm.user.czkt");
System.out.println(u.getUserName());
}
@Test
public void testExpire() throws InterruptedException {//超时失效
User user = new User("xiaomin","123456",1,null);
ValueOperations<String,User> operations=redisTemplate.opsForValue();
operations.set("expire",user,100,TimeUnit.MILLISECONDS);
Thread.sleep(1000);
boolean exists = redisTemplate.hasKey("expire");
if(exists){
System.out.println("exists is true");
}else{
System.out.println("exists is false");
}
}
@Test
public void testHash(){//操作哈希
HashOperations<String,Object,Object> hash = redisTemplate.opsForHash();
hash.put("hash","name","xiaomin");
String v = (String)hash.get("hash","name");
System.out.println(v);
}
@Test
public void testList(){
ListOperations<String,String> list = redisTemplate.opsForList();
list.leftPush("list","xiaomin");
list.leftPush("list","xiaohong");
list.leftPush("list","xiaoqiang");
String v = (String) list.leftPop("list");
System.out.println(v.toString());
}
}
StringRedisTemplate 和 RedisTemplate 区别点:
- 两者的关系是StringRedisTemplate 继承 RedisTemplate 。
- 两者的数据是不共通的;也就是说 StringRedisTemplate 只能管理StringRedisTemplate 里面的数据,RedisTemplate 只能管理 RedisTemplate 中的数据。
- 其实他们两者之间的区别主要在于他们使用的序列化类:
– RedisTemplate 使用的是JdkSerializationRedisSerializer,存入数据会将数据先序列化成字节数组然后在存入 Redis 数据库。
– StringRedisTemplate 使用的是StringRedisSerializer - 使用时注意事项:
当你的 redis数据库里面本来存的是字符串数据或者你要存取的數据就是字符串类型数据的时候,那么你就使用StringRedisTemplate 即可。