Linux安装Redis单机、集群,Redis五种常用数据类型实战及运用场景
一.安装Redis单机版
1.1 下载Redis安装包 推荐大家直接下载我的
链接: pan.baidu.com/s/1f7ALZLAv… 提取码: pu2e
1.2 在linux中输入如下命令
1.3 上传redis-5.0.0.tar.gz到/usr/local路径下
1.4 解压redis-5.0.0.tar.gz
[root@VM-12-10-centos ~]# cd /usr/local/
[root@VM-12-10-centos local]# ls
bin etc games include jdk1.8 lib lib64 libexec maven node-v15.14.0-linux-x64 qcloud redis-5.0.0.tar.gz sbin share src
[root@VM-12-10-centos local]# tar xzvf redis-5.0.0.tar.gz
1.5 安装redis-5.0.0.tar.gz
[root@VM-12-10-centos local]# cd redis-5.0.0
[root@VM-12-10-centos redis-5.0.0]# make
[root@VM-12-10-centos redis-5.0.0]# cd src
[root@VM-12-10-centos src]# make install PREFIX=/usr/local/redis
1.6 移动配置文件到安装目录下
[root@VM-12-10-centos redis-5.0.0]# cd ../
[root@VM-12-10-centos redis-5.0.0]# mkdir /usr/local/redis/etc
[root@VM-12-10-centos redis-5.0.0]# mv redis.conf /usr/local/redis/etc
1.7 配置redis后台启动
## 将daemonize no 改成daemonize yes
[root@VM-12-10-centos redis-5.0.0]# vi /usr/local/redis/etc/redis.conf
1.8 将redis加入到开机启动
## 在里面添加内容:/usr/local/redis/bin/redis-server /usr/local/redis/etc/redis.conf
[root@VM-12-10-centos redis-5.0.0]# vi /etc/rc.local
1.7 开启redis
[root@VM-12-10-centos redis-5.0.0]# /usr/local/redis/bin/redis-server /usr/local/redis/etc/redis.conf
1.8 重开一个服务器窗口 将redis-cli,redis-server拷贝到bin下,让redis-cli指令可以在任意目录下直接使用
[root@VM-12-10-centos ~]# cp /usr/local/redis/bin/redis-server /usr/local/bin/
[root@VM-12-10-centos ~]# cp /usr/local/redis/bin/redis-cli /usr/local/bin/
1.9 设置redis密码
[root@VM-12-10-centos ~]# redis-cli
127.0.0.1:6379> config set requirepass ******
OK
## 设置密码过后 如果你没有通过密码登录 则在redis-cli操作不了命令 需要使用auth 密码
[root@VM-12-10-centos ~]# redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379> keys *
(error) NOAUTH Authentication required.
127.0.0.1:6379> auth ******
OK
127.0.0.1:6379> set index 1
OK
127.0.0.1:6379> keys *
1) "index"
这里设置的密码 重启redis服务就失效了 如果需要配置密码 最好是去/usr/local/redis/etc/redis.conf设置密码 下面会讲到
2.0 让外网能够访问redis 打开服务器安全组,防火墙
[root@VM-12-10-centos ~]# systemctl start firewalld
[root@VM-12-10-centos ~]# firewall-cmd --zone=public --add-port=6379/tcp --permanent
[root@VM-12-10-centos ~]# systemctl restart firewalld
[root@VM-12-10-centos ~]# firewall-cmd --zone=public --list-ports
2.1 此时 虽然防火墙开放了6379端口,但是外网还是无法访问的
因为redis监听的是127.0.0.1:6379,并不监听外网的请求 把文件夹目录里的redis.conf配置文件里的bind 127.0.0.1前面加 #注释掉 并修改protected-mode为no
[root@VM-12-10-centos ~]# vi /usr/local/redis/etc/redis.conf //建议用文本打开
修改完/usr/local/redis/etc/redis.conf 记得重启redis服务 这里推荐先杀死进程后 在重新启动redis服务 这里重新启动服务时 之前设置的密码失效 我们可以在配置文件中直接设置密码 这个是永久生效 requirepass ****** 然后在重新启动redis服务
[root@VM-12-10-centos ~]# ps -ef | grep redis
root 25203 1 0 19:53 ? 00:00:01 /usr/local/redis/bin/redis-server 127.0.0.1:6379
root 28840 27270 0 20:19 pts/1 00:00:00 grep --color=auto redis
[root@VM-12-10-centos ~]# kill -9 25203
[root@VM-12-10-centos ~]# /usr/local/redis/bin/redis-server /usr/local/redis/etc/redis.conf
二.安装Redis集群版
2.1 下载Redis安装包 推荐大家直接下载我的
链接: pan.baidu.com/s/1f7ALZLAv… 提取码: pu2e
2.2 准备3台服务器 redis集群最少需要6个节点 所以 每台服务器需启动两个redis服务 修改redis.conf端口号与集群配置即可
43.143.132.109
118.126.91.205
82.157.248.138
2.3 在第一台服务器(43.143.132.109)linux中输入如下命令
2.4 上传redis-5.0.0.tar.gz到/usr/local路径下
2.5 解压redis-5.0.0.tar.gz
[root@VM-24-4-centos ~]# cd /usr/local/
[root@VM-24-4-centos local]# ls
bin etc games include jdk1.8 lib lib64 libexec maven node-v15.14.0-linux-x64 qcloud redis-5.0.0.tar.gz sbin share src
[root@VM-24-4-centos local]# tar xzvf redis-5.0.0.tar.gz
2.6 安装redis-5.0.0.tar.gz 这里的安装与单机不一样 大家可以自行体会
[root@VM-24-4-centos local]# cd redis-5.0.0
[root@VM-24-4-centos redis-5.0.0]# make
2.7 此时执行cd命令切换到解压目录,执行mkdir 7001 7002创建配置文件存放目录
[root@VM-24-4-centos local]# cd redis-5.0.0/
[root@VM-24-4-centos redis-5.0.0]# mkdir 7001 7002
[root@VM-24-4-centos redis-5.0.0]# ls
00-RELEASENOTES 7002 CONTRIBUTING deps Makefile README.md runtest runtest-sentinel src utils
7001 BUGS COPYING INSTALL MANIFESTO redis.conf runtest-cluster sentinel.conf tests
2.8 复制配置redis.conf文件到7001目录下并编辑
[root@VM-24-4-centos redis-5.0.0]# cp redis.conf ./7001
[root@VM-24-4-centos redis-5.0.0]# vim ./7001/redis.conf
需要编辑的内容如下
bind 127.0.0.1 前面加 #注释掉
protected-mode no
port 7001
daemonize yes
pidfile /usr/local/redis-5.0.0/7001/redis-7001.pid
logfile /usr/local/redis-5.0.0/7001/redis-7001.log
dir /usr/local/redis-5.0.0/7001
appendonly yes
cluster-enabled yes
cluster-config-file nodes-7001.conf
2.9 把7001目录下的redis.conf配置文件复制到7002目录下 执行sed -i 's/7001/7002/g' redis.conf将7001替换成7002
[root@VM-24-4-centos redis-5.0.0]# cp /usr/local/redis-5.0.0/7001/redis.conf /usr/local/redis-5.0.0/7002
[root@VM-24-4-centos redis-5.0.0]# cd 7002
[root@VM-24-4-centos 7002]# sed -i 's/7001/7002/g' redis.conf
3.0 其他两台服务器操作与第一台服务器保持一致
3.1 每台服务器启动两个redis节点 分别为7001 7002
[root@VM-24-4-centos redis-5.0.0]# /usr/local/redis-5.0.0/src/redis-server /usr/local/redis-5.0.0/7001/redis.conf
[root@VM-24-4-centos redis-5.0.0]# /usr/local/redis-5.0.0/src/redis-server /usr/local/redis-5.0.0/7002/redis.conf
[root@VM-24-4-centos redis-5.0.0]# ps -ef | grep redis
root 2217 23222 0 20:33 pts/1 00:00:00 grep --color=auto redis
root 29590 1 0 20:07 ? 00:00:01 /usr/local/redis-5.0.0/src/redis-server *:7002 [cluster]
root 29721 1 0 20:08 ? 00:00:01 /usr/local/redis-5.0.0/src/redis-server *:7001 [cluster]
3.2 三台服务器启动成功后 需要进行集群配置
这里的每台服务器 需要关闭防火墙systemctl stop firewalld,同时开放服务器安全组端口号7001 7002.
三台服务器,启动6个实例,形成三主三从,其中存储相同数据的主从节点不能落在同一台机器上,目的是防止部署redis的虚拟机宕机从而造成主从节点全部失效,所以为了使用主从节点不落在同一台机器上,使用如下命令:每台ip+port交叉,执行命令后出现如下图所示表示redis集群创建成功
[root@VM-12-10-centos redis-5.0.0]# /usr/local/redis-5.0.0/src/redis-cli --cluster create --cluster-replicas 1 118.126.91.205:7001 118.126.91.205:7002 43.143.132.109:7001 43.143.132.109:7002 82.157.248.138:7001 82.157.248.138:7002
# 根据提示输入yes
这里的 118.126.91.205:7001,43.143.132.109:7001,82.157.248.138:7001 为主节点 负责写,118.126.91.205:7002,43.143.132.109:7002,82.157.248.138:7002为从节点 负责读。
3.3 登录客户端,测试集群
[root@VM-12-10-centos redis-5.0.0]# /usr/local/redis-5.0.0/src/redis-cli -c -p 7001
127.0.0.1:7001> cluster info
127.0.0.1:7001> cluster nodes
3.4 集群效果演示
在其中一个服务器上连接redis客户端,set一个值
在另外一个服务器上 get这个值
三.Redis项目实战(RedisTemplate五大数据类型使用)
以下放入代码 大家创建springboot项目复制粘贴类文件即可
3.1 项目目录
3.2 项目代码
pom.xml
<dependencies>
<!--Springboot项目自带 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--Springboot Web项目 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.28</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
application.yml
server:
port: 8080
spring:
#Redis相关配置
redis:
host: 118.126.91.205
port: 6379
password: ******
database: 0
jedis:
#Redis连接池配置
pool:
max-active: 8 #最大连接数
max-wait: 1ms #连接池最大阻塞等待时间
max-idle: 4 #连接池中的最大空闲连接
min-idle: 0 #连接池中的最小空闲连接
RedisConfig
package com.weige.javaskillpoint.config;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate redisTemplate = new StringRedisTemplate(connectionFactory);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
redisTemplate.setValueSerializer(stringRedisSerializer);
redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setHashKeySerializer(stringRedisSerializer);
redisTemplate.setHashValueSerializer(stringRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
启动类加@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) 因为没有连接数据源 这里需要规避掉
package com.weige.javaskillpoint;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class JavaSkillPointApplication {
public static void main(String[] args) {
SpringApplication.run(JavaSkillPointApplication.class, args);
}
}
JavaSkillPointApplicationTests
RedisTemplate中String语法命令
package com.weige.javaskillpoint;
import com.alibaba.fastjson.JSON;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.ZSetOperations;
import java.util.*;
import java.util.concurrent.TimeUnit;
@SpringBootTest
class JavaSkillPointApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void TestString() {
// String语法命令
// set(K key, V value) 新增一个字符串类型的值,key是键,value是值。
redisTemplate.opsForValue().set("test", "666");
// get(Object key) 获取key键对应的值。
String test = (String) redisTemplate.opsForValue().get("test");
// append(K key, String value) 在原有的值基础上新增字符串到末尾 与new StringBuffer().append()含义一致
redisTemplate.opsForValue().append("testAppend", "天下");
// redisTemplate.opsForValue().append("testAppend", "无贼");
String appTestValueAppend = (String) redisTemplate.opsForValue().get("testAppend");
System.out.println("通过append(K key, String value)方法修改后的字符串:" + appTestValueAppend);
// getAndSet(K key, V value) 获取原来的key并重新赋值
System.out.println((String) redisTemplate.opsForValue().get("test"));
redisTemplate.opsForValue().getAndSet("test", "刘德华");
System.out.println((String) redisTemplate.opsForValue().get("test"));
// setBit(K key, long offset, boolean value) 我们知道 'a' 的ASCII码是 97。转换为二进制是:01100001。offset的学名叫做“偏移” 。
// 二进制中的每一位就是offset值啦,比如在这里 offset 0 等于 ‘0’ ,offset 1等于'1' ,offset2等于'1',offset 7 等于'1' ,
// 没错,offset是从左往右计数的,也就是从高位往低位。我们通过SETBIT 命令将 andy中的 'a' 变成 'b' 应该怎么变呢?
// 也就是将 01100001 变成 01100010 (b的ASCII码是98),这个很简单啦,也就是将'a'中的offset 6从0变成1,将offset 7 从1变成0 。
redisTemplate.opsForValue().set("a", "a");
System.out.println((String) redisTemplate.opsForValue().get("a"));
redisTemplate.opsForValue().setBit("a", 6, true);
redisTemplate.opsForValue().setBit("a", 7, false);
System.out.println((String) redisTemplate.opsForValue().get("a"));
// getBit(K key, long offset) 判断指定的位置ASCII码的bit位是否为1。的ASCII码为01100010 所以第一,二,六位为true。下角标从0开始
redisTemplate.opsForValue().set("b", "b");
System.out.println(redisTemplate.opsForValue().getBit("b", 6));
// size(K key) 获取指定字符串的长度。 数字,英文单个长度为1,中文为3。
redisTemplate.opsForValue().set("size", "123");
System.out.println("通过size(K key)方法获取字符串的长度:" + redisTemplate.opsForValue().size("size"));
// increment(K key, double delta) 没有则新增doubleKey并赋值value为5 有这个key值则进行累加 每次加5
double doubleValueDouble = redisTemplate.opsForValue().increment("doubleKey", 5);
System.out.println("通过increment(K key, double delta)方法以增量方式存储double值:" + doubleValueDouble);
// increment(K key, long delta) 没有则新增doubleKey并赋值value为6 有这个key值则进行累加 每次加6
long longValueDouble = redisTemplate.opsForValue().increment("longKey", 6);
System.out.println("通过increment(K key, long delta)方法以增量方式存储long值:" + longValueDouble);
// setIfAbsent(K key, V value) 如果键不存在则新增,存在则不改变已经有的值。
redisTemplate.opsForValue().set("setIfAbsent", "1");
System.out.println(redisTemplate.opsForValue().get("setIfAbsent"));
redisTemplate.opsForValue().setIfAbsent("setIfAbsent", "2");
System.out.println(redisTemplate.opsForValue().get("setIfAbsent"));
redisTemplate.opsForValue().setIfAbsent("newSetIfAbsent", "2");
System.out.println(redisTemplate.opsForValue().get("newSetIfAbsent"));
// set(K key, V value, long timeout, TimeUnit unit) 设置变量值的过期时间。
// TimeUnit.DAYS(天) TimeUnit.HOURS(小时) TimeUnit.MINUTES(分) TimeUnit.SECONDS(秒)
// 5秒后过期
redisTemplate.opsForValue().set("timeOutKey", "timeOut", 5, TimeUnit.SECONDS);
System.out.println(redisTemplate.opsForValue().get("timeOutKey"));
// set(K key, V value, long offset) 覆盖从指定位置开始的值。
// 比如key为absentKey value为aa,set("absentKey","dd",1)是指从角标为1的地方开始覆盖为bb 即abb
redisTemplate.opsForValue().set("absentKey", "aa");
redisTemplate.opsForValue().set("absentKey", "dd", 1);
String overrideString = (String) redisTemplate.opsForValue().get("absentKey");
System.out.println("通过set(K key, V value, long offset)方法覆盖部分的值:" + overrideString);
// multiSet(Map<? extends K,? extends V> map) 设置map集合到redis。
Map valueMap = new HashMap();
valueMap.put("valueMap1", "map1");
valueMap.put("valueMap2", "map2");
valueMap.put("valueMap3", "map3");
redisTemplate.opsForValue().multiSet(valueMap);
// multiGet(Collection<K> keys) 根据集合取出对应的value值。
Map map1 = new HashMap();
map1.put("key1", "value11");
map1.put("key2", "value22");
map1.put("key3", "value33");
List list1 = new ArrayList();
list1.add("key1");
list1.add("key2");
list1.add("key3");
redisTemplate.opsForValue().multiSetIfAbsent(map1);
List<String> valueList1 = redisTemplate.opsForValue().multiGet(list1);
for (String value : valueList1) {
System.out.println("通过multiGet(Collection<K> keys)方法获取map值:" + value);
}
// multiSetIfAbsent(Map<? extends K,? extends V> map) 如果对应的map集合名称不存在,则添加;如果存在则不做修改。
Map valueMap1 = new HashMap();
valueMap1.put("valueMap1", "map1");
valueMap1.put("valueMap2", "map2");
valueMap1.put("valueMap3", "map3");
redisTemplate.opsForValue().multiSetIfAbsent(valueMap1);
List list2 = new ArrayList();
list2.add("valueMap1");
list2.add("valueMap2");
list2.add("valueMap3");
// 这个地方再次put是不会生效的,key存在则不做修改。
valueMap.put("valueMap4", "map4");
redisTemplate.opsForValue().multiSetIfAbsent(valueMap1);
List<String> valueList2 = redisTemplate.opsForValue().multiGet(list2);
for (String value : valueList2) {
System.out.println("通过multiGet(Collection<K> keys)方法获取map值:" + value);
}
}
}
RedisTemplate中Hash语法命令
package com.weige.javaskillpoint;
import com.alibaba.fastjson.JSON;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.ZSetOperations;
import java.util.*;
import java.util.concurrent.TimeUnit;
@SpringBootTest
class JavaSkillPointApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void TestHash(){
// put(H key, HK hashKey, HV value) 新增hashMap值
Map<Object,Object> b1 = new HashMap();
b1.put("name","刘德华");
b1.put("sex","18");
Map<Object,Object> b2 = new HashMap();
b2.put("name","周润发");
b2.put("sex","22");
List<Map<Object,Object>> mapList = new ArrayList<>();
mapList.add(b1);
mapList.add(b2);
redisTemplate.opsForHash().put("all", "a", "1");
System.out.println(redisTemplate.opsForHash().get("all","a"));
redisTemplate.opsForHash().put("all", "b1", JSON.toJSONString(b1));
System.out.println(redisTemplate.opsForHash().get("all","b1"));
redisTemplate.opsForHash().put("all", "b2", JSON.toJSONString(b2));
System.out.println(redisTemplate.opsForHash().get("all","b2"));
redisTemplate.opsForHash().put("all", "c", JSON.toJSONString(mapList));
System.out.println(redisTemplate.opsForHash().get("all","c"));
// 设置过期时间
// TimeUnit.DAYS(天) TimeUnit.HOURS(小时) TimeUnit.MINUTES(分) TimeUnit.SECONDS(秒)
redisTemplate.opsForHash().put("expiredTime", "expired", "1");
redisTemplate.expire("expiredTime" ,10, TimeUnit.SECONDS);
// 获取变量中的键值对 并循环打印
Map<Object,Object> all = redisTemplate.opsForHash().entries("all");
for (Map.Entry<Object, Object> key : all.entrySet()) {
System.out.println(key);
System.out.println(key.getKey());
System.out.println(key.getValue());
}
// 获取变量中的指定map键是否有值,如果存在该map键则获取值,没有则返回null
String all1 = (String) redisTemplate.opsForHash().get("all", "b1");
String all2 = (String) redisTemplate.opsForHash().get("all", "c");
String all3 = (String) redisTemplate.opsForHash().get("all", "q");
System.out.println(all1);
System.out.println(all2);
System.out.println(all3);
// 以map集合的形式添加键值对
Map<Object,Object> maps = new HashMap();
maps.put("name","周星驰");
maps.put("sex","35");
redisTemplate.opsForHash().putAll("keyMap", maps);
System.out.println((String) redisTemplate.opsForHash().get("keyMap","name"));
Map<Object,Object> keyMapAll = redisTemplate.opsForHash().entries("keyMap");
for (Map.Entry<Object, Object> key : keyMapAll.entrySet()) {
System.out.println(key);
System.out.println(key.getKey());
System.out.println(key.getValue());
}
// 仅当hashKey不存在时才设置
redisTemplate.opsForHash().put("putIfAbsent","aa","1");
System.out.println(redisTemplate.opsForHash().get("putIfAbsent","aa"));
redisTemplate.opsForHash().putIfAbsent("putIfAbsent","aa","2");
// 无变化
System.out.println(redisTemplate.opsForHash().get("putIfAbsent","aa"));
redisTemplate.opsForHash().putIfAbsent("putIfAbsent","bb","4");
System.out.println(redisTemplate.opsForHash().get("putIfAbsent","bb"));
// 删除一个或者多个hash表字段
redisTemplate.opsForHash().put("deleKey","a","1");
redisTemplate.opsForHash().put("deleKey","b","2");
redisTemplate.opsForHash().put("deleKey","c","3");
System.out.println(redisTemplate.opsForHash().get("deleKey","a"));
System.out.println(redisTemplate.opsForHash().get("deleKey","b"));
System.out.println(redisTemplate.opsForHash().get("deleKey","c"));
redisTemplate.opsForHash().delete("deleKey", "a","b");
System.out.println(redisTemplate.opsForHash().get("deleKey","a"));
System.out.println(redisTemplate.opsForHash().get("deleKey","b"));
System.out.println(redisTemplate.opsForHash().get("deleKey","c"));
// 查看hash表中指定字段是否存在
redisTemplate.opsForHash().put("queryKey","e","1");
System.out.println( redisTemplate.opsForHash().hasKey("queryKey", "e"));
redisTemplate.opsForHash().delete("queryKey", "e");
System.out.println( redisTemplate.opsForHash().hasKey("queryKey", "e"));
// 给哈希表key中的指定字段的整数值加上增量increment.如果没有对应的key或hashKey,则会自动新增hashMap值value为increment
redisTemplate.opsForHash().put("incrementKey","v","1");
redisTemplate.opsForHash().increment("incrementKey", "v", 9);
System.out.println(redisTemplate.opsForHash().get("incrementKey","v"));
// key或hashKey不存在时
redisTemplate.opsForHash().increment("noIncrementKey", "noV", 6);
System.out.println(redisTemplate.opsForHash().get("noIncrementKey","noV"));
// 获取key中所有hashKey表中的字段 [a, b, c, d]
redisTemplate.opsForHash().put("keyAll", "a", "1");
redisTemplate.opsForHash().put("keyAll", "b", "2");
redisTemplate.opsForHash().put("keyAll", "c", "3");
redisTemplate.opsForHash().put("keyAll", "d", "4");
System.out.println(redisTemplate.opsForHash().keys("keyAll"));
// 获取key表中hashKey字段的数量 4
System.out.println(redisTemplate.opsForHash().size("keyAll"));
// 获获取key中所有hashKey表中的值 [1, 2, 3, 4]
System.out.println(redisTemplate.opsForHash().values("keyAll"));
// 匹配获取键值对,ScanOptions.NONE为获取全部键对
Cursor<Map.Entry<String, Object>> keyAll = redisTemplate.opsForHash().scan("keyAll", ScanOptions.NONE);
while (keyAll.hasNext()){
Map.Entry<String, Object> entry = keyAll.next();
System.out.println("key:" + entry.getKey() + "," + "value:" + entry.getValue());
}
}
}
RedisTemplate中List语法命令
package com.weige.javaskillpoint;
import com.alibaba.fastjson.JSON;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.ZSetOperations;
import java.util.*;
import java.util.concurrent.TimeUnit;
@SpringBootTest
class JavaSkillPointApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void TestList(){
// List类型命令
// 把多个值存入List中(value可以是多个值,也可以是一个Collection value)
redisTemplate.opsForList().leftPushAll("list1", "11","22","33","66");
// 取列表指定范围内的元素(start开始位置, 0是开始位置,end 结束位置, -1返回所有)
System.out.println(redisTemplate.opsForList().range("list1", 0, 0));
System.out.println(redisTemplate.opsForList().range("list1", 0, 1));
System.out.println(redisTemplate.opsForList().range("list1", 0, 2));
System.out.println(redisTemplate.opsForList().range("list1", 0, -1));
// 通过索引获取列表中的元素
redisTemplate.opsForList().leftPushAll("list2", "5","6","7");
System.out.println(redisTemplate.opsForList().index("list1", 1));
// 存储在list的头部,即添加一个就把它放在最前面的索引处
redisTemplate.opsForList().leftPushAll("list3", "51","61","71");
// 71
System.out.println(redisTemplate.opsForList().index("list3", 0));
redisTemplate.opsForList().leftPushAll("list3", "81");
// 81
System.out.println(redisTemplate.opsForList().index("list3", 0));
// List存在的时候再加入
redisTemplate.opsForList().leftPushIfPresent("list4", "91");
// null
System.out.println(redisTemplate.opsForList().index("list4", 0));
redisTemplate.opsForList().leftPushIfPresent("list3", "91");
// 91
System.out.println(redisTemplate.opsForList().index("list3", 0));
// 如果pivot处值存在则在pivot前面添加
redisTemplate.opsForList().leftPushAll("list5", "101","102");
// 104不存在 所以不会添加
redisTemplate.opsForList().leftPush("list5","104","103");
System.out.println(redisTemplate.opsForList().range("list5", 0, -1));
redisTemplate.opsForList().leftPush("list5","102","103");
System.out.println(redisTemplate.opsForList().range("list5", 0, -1));
// 按照先进先出的顺序来添加(value可以是多个值,或者是Collection var2)
redisTemplate.opsForList().rightPush("list6", "20");
redisTemplate.opsForList().rightPushAll("list6", "21","22","23");
System.out.println(redisTemplate.opsForList().range("list6", 0, -1));
// 在pivot元素的右边添加值
redisTemplate.opsForList().rightPush("list6", "20", "20.1");
System.out.println(redisTemplate.opsForList().range("list6", 0, -1));
// 设置指定索引处元素的值
redisTemplate.opsForList().set("list6", 2, "20.2");
System.out.println(redisTemplate.opsForList().range("list6", 0, -1));
// 移除并获取列表中第一个元素(如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止)
redisTemplate.opsForList().leftPop("list6");
System.out.println(redisTemplate.opsForList().range("list6", 0, -1));
redisTemplate.opsForList().leftPop("list6", 10, TimeUnit.MINUTES);
System.out.println(redisTemplate.opsForList().range("list6", 0, -1));
// 移除并获取列表最后一个元素
redisTemplate.opsForList().rightPop("list6");
System.out.println(redisTemplate.opsForList().range("list6", 0, -1));
redisTemplate.opsForList().rightPop("list6", 10, TimeUnit.MINUTES);
System.out.println(redisTemplate.opsForList().range("list6", 0, -1));
// 从一个队列的右边弹出一个元素并将这个元素放入另一个指定队列的最左边
redisTemplate.opsForList().leftPushAll("list7","11","22","33");
redisTemplate.opsForList().leftPushAll("list8","55","66","77");
redisTemplate.opsForList().rightPopAndLeftPush("list7", "list8");
System.out.println(redisTemplate.opsForList().range("list7", 0, -1));
System.out.println(redisTemplate.opsForList().range("list8", 0, -1));
redisTemplate.opsForList().rightPopAndLeftPush("list7", "list8",10,TimeUnit.SECONDS);
System.out.println(redisTemplate.opsForList().range("list7", 0, -1));
System.out.println(redisTemplate.opsForList().range("list8", 0, -1));
// 删除集合中值等于value的元素(index=0, 删除所有值等于value的元素; index>0, 从头部开始删除第一个值等于value的元素; index<0, 从尾部开始删除第一个值等于value的元素)
redisTemplate.opsForList().leftPushAll("list9","100","100","101","102","103","100","104","105","100");
redisTemplate.opsForList().remove("list9", 1, "100");
System.out.println(redisTemplate.opsForList().range("list9", 0, -1));
redisTemplate.opsForList().remove("list9", -1, "100");
System.out.println(redisTemplate.opsForList().range("list9", 0, -1));
redisTemplate.opsForList().remove("list9", 0, "100");
System.out.println(redisTemplate.opsForList().range("list9", 0, -1));
// 将List列表进行剪裁
redisTemplate.opsForList().leftPushAll("list10","100","101","102","103","104","105");
redisTemplate.opsForList().trim("list10", 0, 3);
System.out.println(redisTemplate.opsForList().range("list10", 0, -1));
// 获取当前key的List列表长度
System.out.println(redisTemplate.opsForList().size("list10"));
}
}
RedisTemplate中Set语法命令
package com.weige.javaskillpoint;
import com.alibaba.fastjson.JSON;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.ZSetOperations;
import java.util.*;
import java.util.concurrent.TimeUnit;
@SpringBootTest
class JavaSkillPointApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void TestSet(){
// Set类型命令
// 添加元素
redisTemplate.opsForSet().add("set1","666","777","888","999");
System.out.println(redisTemplate.opsForSet().members("set1"));
// 移除元素(单个值、多个值)
redisTemplate.opsForSet().remove("set1", "666");
System.out.println(redisTemplate.opsForSet().members("set1"));
// 删除并且返回一个随机的元素
redisTemplate.opsForSet().pop("set1");
System.out.println(redisTemplate.opsForSet().members("set1"));
// 获取集合的大小
System.out.println(redisTemplate.opsForSet().size("set1"));
// 判断集合是否包含value
redisTemplate.opsForSet().add("set2","12","13","14","15");
System.out.println(redisTemplate.opsForSet().isMember("set2", "12"));
// 获取两个集合的交集(key对应的无序集合与otherKey对应的无序集合求交集)
redisTemplate.opsForSet().add("set3","2","3","4","5","0");
redisTemplate.opsForSet().add("set4","5","1","2","0");
System.out.println(redisTemplate.opsForSet().intersect("set3", "set4"));
// 获取多个集合的交集(Collection var2)
redisTemplate.opsForSet().add("set5","10","1","6","0");
List list = new ArrayList();
list.add("set4");
list.add("set5");
System.out.println(redisTemplate.opsForSet().intersect("set3",list));
// key集合与otherKey集合的交集存储到destKey集合中(其中otherKey可以为单个值或者集合)
redisTemplate.opsForSet().intersectAndStore("set3",list,"set6");
System.out.println(redisTemplate.opsForSet().members("set6"));
// 获取两个或者多个集合的并集(otherKeys可以为单个值或者是集合)
redisTemplate.opsForSet().add("set7","11","22","33","44");
redisTemplate.opsForSet().add("set8","21","31","41","44");
System.out.println(redisTemplate.opsForSet().union("set7", "set8"));
System.out.println(redisTemplate.opsForSet().union("set7", list));
// key集合与otherKey集合的并集存储到destKey中(otherKeys可以为单个值或者是集合)
redisTemplate.opsForSet().unionAndStore("set8", list,"set9");
System.out.println(redisTemplate.opsForSet().members("set9"));
// 获取两个或者多个集合的差集(otherKeys可以为单个值或者是集合)
redisTemplate.opsForSet().add("set10","1","2","3","4","5");
redisTemplate.opsForSet().add("set11","1","2","3");
System.out.println(redisTemplate.opsForSet().difference("set10", "set11"));
// 差集存储到destKey中(otherKeys可以为单个值或者集合)
redisTemplate.opsForSet().differenceAndStore("set10", "set11","set12");
System.out.println(redisTemplate.opsForSet().members("set12"));
// 随机获取集合中的一个元素
System.out.println(redisTemplate.opsForSet().randomMember("set12"));
// 获取集合中的所有元素
redisTemplate.opsForSet().members("set10");
// 随机获取集合中count个元素
System.out.println(redisTemplate.opsForSet().randomMembers("set10", 3));
// 获取多个key无序集合中的元素(去重),count表示个数
System.out.println(redisTemplate.opsForSet().distinctRandomMembers("set10", 3));
// 遍历set类似于Interator(ScanOptions.NONE为显示所有的)
Cursor set10 = redisTemplate.opsForSet().scan("set10", ScanOptions.NONE);
while (set10.hasNext()){
System.out.println("value:" +set10.next());
}
}
}
RedisTemplate中zSet语法命令
package com.weige.javaskillpoint;
import com.alibaba.fastjson.JSON;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.ZSetOperations;
import java.util.*;
import java.util.concurrent.TimeUnit;
@SpringBootTest
class JavaSkillPointApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void TestZset(){
// zSet数据类型命令
// 添加元素(有序集合是按照元素的score值由小到大进行排列)
redisTemplate.opsForZSet().add("zset1","9",1);
redisTemplate.opsForZSet().add("zset1","9",2);
redisTemplate.opsForZSet().add("zset1","10",2);
redisTemplate.opsForZSet().add("zset1","11",0.1);
redisTemplate.opsForZSet().add("zset1","12",0.3);
redisTemplate.opsForZSet().add("zset1","13",1.5);
// 删除对应的value,value可以为多个值
redisTemplate.opsForZSet().remove("zset1","10");
// 增加元素的score值,并返回增加后的值
System.out.println(redisTemplate.opsForZSet().incrementScore("zset11", "9", 16));
// 返回元素在集合的排名,有序集合是按照元素的score值由小到大排列
System.out.println(redisTemplate.opsForZSet().rank("zset1", "11"));
// 返回元素在集合的排名,按元素的score值由大到小排列
System.out.println(redisTemplate.opsForZSet().reverseRank("zset1", "11"));
// 获取集合中给定区间的元素(start 开始位置,end 结束位置, -1查询所有)
Set zset1 = redisTemplate.opsForZSet().reverseRangeWithScores("zset1", 0, -1);
for (Object o : zset1) {
System.out.println("value:" + o);
}
// 按照Score值查询集合中的元素,结果从小到大排序
Set zset11 = redisTemplate.opsForZSet().reverseRangeByScore("zset1", 1, 2);
for (Object o : zset11) {
System.out.println("value:" + o);
}
// 从高到低的排序集中获取分数在最小和最大值之间的元素
Set zset12 = redisTemplate.opsForZSet().reverseRangeByScore("zset1", 1, 2, 0, -1);
for (Object o : zset12) {
System.out.println("value:" + o);
}
// 根据score值获取集合元素数量
redisTemplate.opsForZSet().add("zset2","12",1);
redisTemplate.opsForZSet().add("zset2","13",1.5);
redisTemplate.opsForZSet().add("zset2","14",2);
redisTemplate.opsForZSet().add("zset2","15",3);
redisTemplate.opsForZSet().add("zset2","16",4);
redisTemplate.opsForZSet().add("zset2","17",5);
System.out.println(redisTemplate.opsForZSet().count("zset2",1,3));
// 获取集合的大小
System.out.println(redisTemplate.opsForZSet().size("zset2"));
System.out.println(redisTemplate.opsForZSet().zCard("zset2"));
// 获取集合中key、value元素对应的score值
System.out.println(redisTemplate.opsForZSet().score("zset2", "12"));
//移除指定索引位置处的成员
redisTemplate.opsForZSet().removeRange("zset2",0,1);
System.out.println(redisTemplate.opsForZSet().range("zset2", 0, -1));
// 移除指定score范围的集合成员
redisTemplate.opsForZSet().removeRangeByScore("zset2",4,5);
System.out.println(redisTemplate.opsForZSet().range("zset2", 0, -1));
// 获取key和otherKey的并集并存储在destKey中(其中otherKeys可以为单个字符串或者字符串集合)
redisTemplate.opsForZSet().add("zset3","1",1);
redisTemplate.opsForZSet().add("zset3","2",2);
redisTemplate.opsForZSet().add("zset3","3",3);
redisTemplate.opsForZSet().add("zset4","3",4);
redisTemplate.opsForZSet().add("zset4","4",5);
redisTemplate.opsForZSet().add("zset4","5",3);
redisTemplate.opsForZSet().add("zset5","10",6);
redisTemplate.opsForZSet().add("zset5","11",7);
redisTemplate.opsForZSet().add("zset5","12",8);
redisTemplate.opsForZSet().unionAndStore("zset3","zset4","zset6");
System.out.println(redisTemplate.opsForZSet().range("zset6",0,-1));
List list = new ArrayList();
list.add("zset4");
list.add("zset5");
redisTemplate.opsForZSet().unionAndStore("zset3",list,"zset7");
System.out.println(redisTemplate.opsForZSet().range("zset7",0,-1));
// 获取key和otherKey的交集并存储在destKey中(其中otherKeys可以为单个字符串或者字符串集合)
redisTemplate.opsForZSet().add("zset8","1",1);
redisTemplate.opsForZSet().add("zset8","3",2);
redisTemplate.opsForZSet().add("zset9","3",3);
redisTemplate.opsForZSet().add("zset9","4",4);
redisTemplate.opsForZSet().add("zset10","5",5);
redisTemplate.opsForZSet().add("zset10","6",5);
redisTemplate.opsForZSet().intersectAndStore("zset8","zset9","zset11");
System.out.println(redisTemplate.opsForZSet().range("zset11", 0, -1));
List list1 = new ArrayList();
list1.add("zset9");
list1.add("zset10");
redisTemplate.opsForZSet().intersectAndStore("zset8",list1,"zset12");
System.out.println(redisTemplate.opsForZSet().range("zset12",0,-1));
// 遍历集合(和iterator一模一样)
redisTemplate.opsForZSet().add("zset13","刘德华",1);
redisTemplate.opsForZSet().add("zset13","周润发",2);
redisTemplate.opsForZSet().add("zset13","周星驰",3);
Cursor<ZSetOperations.TypedTuple<Object>> scan = redisTemplate.opsForZSet().scan("zset13",ScanOptions.NONE);
while (scan.hasNext()){
ZSetOperations.TypedTuple<Object> item = scan.next();
System.out.println(item.getValue() + ":" + item.getScore());
}
}
}
四.Redis的常用场景
4.1 缓存
缓存现在几乎是所有中大型网站都在用的必杀技,合理的利用缓存不仅能够提升网站访问速度,还能大大降低数据库的压力。Redis提供了键过期功能,也提供了灵活的键淘汰策略,所以,现在Redis用在缓存的场合非常多。
4.2 排行榜
很多网站都有排行榜应用的,如京东的月度销量榜单、商品按时间的上新排行榜等。Redis提供的有序集合数据类构能实现各种复杂的排行榜应用。
4.3 计数器
什么是计数器,如电商网站商品的浏览量、视频网站视频的播放数等。为了保证数据实时效,每次浏览都得给+1,并发量高时如果每次都请求数据库操作无疑是种挑战和压力。Redis提供的incr命令来实现计数器功能,内存操作,性能非常好,非常适用于这些计数场景。
4.4 分布式会话
集群模式下,在应用不多的情况下一般使用容器自带的session复制功能就能满足,当应用增多相对复杂的系统中,一般都会搭建以Redis等内存数据库为中心的session服务,session不再由容器管理,而是由session服务及内存数据库管理。
4.5 分布式锁
在很多互联网公司中都使用了分布式技术,分布式技术带来的技术挑战是对同一个资源的并发访问,如全局ID、减库存、秒杀等场景,并发量不大的场景可以使用数据库的悲观锁、乐观锁来实现,但在并发量高的场合中,利用数据库锁来控制资源的并发访问是不太理想的,大大影响了数据库的性能。可以利用Redis的setnx功能来编写分布式的锁,如果设置返回1说明获取锁成功,否则获取锁失败,实际应用中要考虑的细节要更多。
4.6 社交网络
点赞、踩、关注/被关注、共同好友等是社交网站的基本功能,社交网站的访问量通常来说比较大,而且传统的关系数据库类型不适合存储这种类型的数据,Redis提供的哈希、集合等数据结构能很方便的的实现这些功能。如在微博中的共同好友,通过Redis的set能够很方便得出。
4.7 最新列表
Redis列表结构,LPUSH可以在列表头部插入一个内容ID作为关键字,LTRIM可用来限制列表的数量,这样列表永远为N个ID,无需查询最新的列表,直接根据ID去到对应的内容页即可。
4.8 消息系统
消息队列是大型网站必用中间件,如ActiveMQ、RabbitMQ、Kafka等流行的消息队列中间件,主要用于业务解耦、流量削峰及异步处理实时性低的业务。Redis提供了发布/订阅及阻塞队列功能,能实现一个简单的消息队列系统。另外,这个不能和专业的消息中间件相比。