盒子
盒子
文章目录
  1. 前言
  2. 说明
  3. 安装
    1. error: jemalloc/jemalloc.h: No such file or directory
  4. PS
  5. 使用
    1. 启动
    2. 中文乱码
    3. 关闭
  6. spring boot 2.x 整合 redis
    1. build.gradle
    2. application.yml
    3. spring config
    4. 使用
    5. 序列化
    6. redis 的连接池
    7. 其它

redis 简单使用

前言

之前在 秒杀系统简单实现 有提到 spring boot 整合 redis,有必要单独提出来讲一下.

说明

redis 一般在学习并发优化,分布式之类的东西时接触到,不严谨地讲,redis 在这些场景被用于提高服务端响应速度.而 redis 到底是啥,结合它是如何来解决前面这个问题的,能更好地理解.

redis 的官方定义是”一个把结构化的数据放在内存中的一个存储系统”.这个定义很开放,你可以用 redis 做数据库,也可以用来缓存或作消息中间件.

redis 的数据放在内存中,这就是它优化服务端响应速度的一个原因.像一般的数据库,如 MySQL,MySQL 的数据存放在磁盘,在不考虑其它原因的情况下,可以直观地认为内存中的数据当然比磁盘中的数据读取地快,所以 redis 起到了优化的作用.

在具体的优化中,redis 一般起缓存作用.在冷启动时,数据仍然通过原有方式获取,然后存放在 redis 中,而之后需要读取数据,就可以直接从 redis 获得.

安装

redis 版本 : 5.0.3

linux 版本 : centos 7

解压版安装,稍微详细点.

下载地址 : https://redis.io/download

解压,打开,执行 make. 可以用 j 参数,执行 make j8,

有可能缺少依赖(在我的环境下,只遇到过缺少依赖的报错),按提示安装缺少的依赖即可.

PS : 使用默认值执行了 make install,会在 /usr/local/bin 生成安装目录,可全局执行 redis 相关命令…

error: jemalloc/jemalloc.h: No such file or directory

执行 make MALLOC=libc

PS

19-7-29 腾讯云重装 CentOS 7.5 , 这次啥问题也没有…

使用

redis-server 是 Redis 服务器

redis-cli 是 Redis 命令行客户端

这俩也是最常使用的 redis 命令.

启动

运行 redis : redis-server

PS : 执行 redis-server 如果遇到某些错误信息,其实当前窗口已经给出了解决办法.看不明白可以搜索引擎查看.(我现在写这篇博文已经不晓得之前遇到过啥问题了…)

打开执行 redis 命令的窗口 : redis-cli

关于启动,主要就是这俩命令.我们需要启动 redis-server,然后在 redis-cli 中对 redis 进行操作.(如增删改数据…)

这里就会遇到问题.

在不进行任何配置的情况下,执行 redis-server 使用的是默认配置.

在默认情况下, redis-server 会在 前台 执行.而我们实际对 redis 进行操作(增删改数据之类的)需要打开 redis-cli.

由于 redis-server 是在前台运行的,如果在想在当前窗口运行 redis-cli 那就得杀掉这个前台进程,然后执行 redis-cli.

但此时, redis-server 已经被关闭了,所以在 redis-cli 执行的操作都没效果.

PS : 如果已经整合到 spring boot,进行数据操作时会报错NOAUTH Authentication required.

如何解决?

解决方案一 : 在一个终端执行 redis-server ,重开一个窗口执行 redis-cli ,然后执行相应操作.

解决方案二 : 通过修改配置文件使之后台启动 redis-server.

后台执行 redis-server ,然后就能在当前窗口执行 redis-cli 啦.

如何做?

修改 /redis/redis.conf 中的 daemonize nodaemonize yes 即可.

启动

redis-server redis.conf

比如 :

进入 /redis/src

执行 ./redis-server ../redis.conf 意思就是以自己的配置(后台执行)来运行 redis-server.

ok.

然后使用命令 ps -ef|grep redis 检查是否后台启动成功.

中文乱码

启动 redis-cli 时加上参数.

1
redis-cli --raw

关闭

spring boot 2.x 整合 redis

我采用的是 gradle + yml.

配置需要在三个地方动手…

  1. gradle 中引入必要依赖.
  2. yml 中完善配置
  3. 添加一个 config 配置类

build.gradle

1
2
3
4
5
6
7
8
9
10
11
// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis
compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-redis', version: '2.1.1.RELEASE'

// https://mvnrepository.com/artifact/com.alibaba/fastjson
compile group: 'com.alibaba', name: 'fastjson', version: '1.2.47'

//必要的
compile('org.apache.commons:commons-pool2:2.6.0')

//spring cache 效果:redis 里的数据删了,spring 仍能查到数据,就是通过它拿到的
compile('org.springframework.boot:spring-boot-starter-cache')

第一个 spring-boot-starer-data-redis 是主要依赖,用于 redis 与 spring boot 交互.

第二个 fastjson 用于 java 对象和 json 对象之间序列化的转换.

第三个 commons-pool ,具体不知道是干嘛的…

搜索得到 : Commons Pool组件提供了一整套用于实现对象池化的框架

大概是维护对象池,提高数据读取速度…

第四个 spring-boot-starter-cache 不要也可以,猜测是 spring 框架的缓存.因为我进行排除对比,有这个依赖时,redis 的数据删除了,spring 仍能不通过数据库拿到数据.删除就不起作用了.

application.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
server:
port: 8082

spring:
# 属性值可以为空,但是不能没有以下字段,否则启动报错
datasource:
url: jdbc:mysql://118.126.test.120:3306/test?serverTimezone=UTC
username:
password:
driver-class-name: com.mysql.jdbc.Driver
# spring boot 2.x 配置方式
redis:
# Redis数据库索引(默认为0)
database: 0
# Redis服务器地址
host: localhost
# Redis服务器连接端口(默认 6379)
port: 6379
# Redis服务器连接密码(默认为空)
password:
# pringboot2.x 需要这样配置
lettuce:
pool:
max-active: 8
max-wait: -1ms
min-idle: 0

主要在后面的 redis 配置…

上面是 spring boot 2.x 的配置方式,下面是旧的配置方式.

1
2
3
4
5
6
7
8
9
10
11
12
13
# spring boot 旧配置方式
spring:
redis:
hostName:
port:
password:
database:
timeout: 0
pool:
max-active: 8
max-wait: -1
max-idle: 8
min-idle: 0

不同点在新的配置方式里,需要手动指定 redis 连接池.

比如还可以:

1
2
3
4
5
6
7
8
9
10
11
12
redis:
port:
host:
password:
database:
timeout:
jedis:
pool:
max-active:
max-idle:
min-idle:
max-wait:

指定 redis 连接池为 jedis…

spring config

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/**
* @description: TODO
* Created by hqweay on 1/1/19 2:07 PM
* 这个配置类仍然是必须的,不然向 redis 插入数据会失败
*/
@Configuration
@EnableCaching
public class RedisConfiguration {

@Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory connectionFactory) {
RedisTemplate template = new RedisTemplate();
template.setConnectionFactory(connectionFactory);

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);

Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

template.setValueSerializer(jackson2JsonRedisSerializer);
template.setKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}


@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);

RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
cacheConfiguration = cacheConfiguration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer));
cacheConfiguration.entryTtl(Duration.ofMinutes(10));
CacheManager cacheManager = new RedisCacheManager(redisCacheWriter, cacheConfiguration);
return cacheManager;

}
}

这一块的使用我还没弄清楚,代码来自网络,整理不当,忘记从哪 copy 的了…

@EnableCaching 注解似乎是与前文在 gradle 引入的 spring-boot-starter-cache 相联系,开启 spring-cache,cacheManager 是为此实现的一个方法.

使用

直接看封装的这个操作类…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Component
public class RedisDao {

@Autowired
private RedisTemplate redisTemplate;

public boolean putProductList(ArrayList<Product> products) {
if (redisTemplate.hasKey("productList")) {
return false;
} else {
redisTemplate.opsForValue().set("productList", products);
}
return true;
}

public ArrayList<Product> getProductList() throws SkillException {
try {
return (ArrayList<Product>) redisTemplate.opsForValue().get("productList");
} catch (SkillException e) {
e.setStatusEnum(REDIS_GET_ERROR);
throw e;
}
}


public void test(){
OrderKey orderKey = new OrderKey();
orderKey.setPhone("1155555");
redisTemplate.opsForValue().set("11",orderKey);
redisTemplate.opsForValue().set("myse","mys");
System.out.println(redisTemplate.opsForValue().get("33"));
}
}

序列化

spring boot 与 redis 交互有两种方式,一个是直接序列化,一个是转化为 json,以字符串格式存储.

这里使用的是 json 存储对象,前面有提到,用 fastjson 把 对象转换为 json 对象(这也是序列化嘛),然后存入 redis.读取的时候,会自动把 json 转换为 Object 对象,自己再转型一下就行了.

比如上面代码中的:

1
(ArrayList<Product>) redisTemplate.opsForValue().get("productList");

redis 的连接池

在上面的配置中有提到,spring boot 使用 redis 的连接池有 Jedis 和 Lettuce.

这两个有啥区别,怎么选型呢?

我在练习秒杀系统时,视频教程用的是 Jedis,但是 spring boot 2.0 以后已经把之前的 Jedis 改为 Lettuce 了.(也是配置改动的原因)

具体有啥区别,搜索有答案,自己也没深入了解.

就用 Lettuce 吧…

其它

学习 redis,各种入门教程会有各种 set,get 等基本命令,但是只是简单使用的话,暂时没必要了解,因为已经被封装了一层,可以直接用 java 操作…