Redis✧数据库
一、Java集成Redis
✧ 方式一:通过Jedis作为java客户端对服务器进行连接
✧ 方式二:通过spring data redis作为客户端进行服务器连接
1、Jedis–Java版客户端
① 入门(依赖✧测试)
- 直接引入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
</parent>
<dependencies>
<!-- spring data redis 组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<!--
1.x 的版本默认采用的连接池技术是 Jedis,
2.0 以上版本默认连接池是 Lettuce,
如果采用 Jedis,需要排除 Lettuce 的依赖。
-->
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- jedis 依赖 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<!-- web 组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- test 组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
- 创建测试类,直接测试向
Linux
的redis
服务器发送请求
public class SpringTest {
@Test
public void test1(){
Jedis jedis=new Jedis("192.168.168.129",6399);
jedis.auth("123456");
System.out.println(jedis.ping());
}
}
//关闭防火墙:
//systemctl status firewalld 查看状态
//systemctl stop firewalld 关闭
记得启动Linux中的redis服务器,并且关闭Linux的防火墙
② 常用方式⭐
(1)配置redis–Application.yml
spring:
redis:
# Redis服务器地址
host: 192.168.168.129
# Redis服务器端口
port: 6399
# Redis服务器密码
password: 123456
# 选择哪个库,默认0库
database: 0
# 连接超时时间
timeout: 10000ms
jedis:
pool:
# 最大连接数,默认8
max-active: 1024
# 最大连接阻塞等待时间,单位毫秒,默认-1ms
max-wait: 10000ms
# 最大空闲连接,默认8
max-idle: 200
# 最小空闲连接,默认0
min-idle: 5
(2)编写Redis配置类Redisconfig.java
- 主要是为了方便获取资源配置一个RedisPool
@Configuration
public class Redisconfig {
//服务器地址
@Value("${spring.redis.host}")
private String host;
//端口
@Value("${spring.redis.port}")
private int port;
//密码
@Value("${spring.redis.password}")
private String password;
//超时时间
@Value("${spring.redis.timeout}")
private String timeout;
//最大连接数
@Value("${spring.redis.jedis.pool.max-active}")
private int maxTotal;
//最大连接阻塞等待时间
@Value("${spring.redis.jedis.pool.max-wait}")
private String maxWaitMillis;
//最大空闲连接
@Value("${spring.redis.jedis.pool.max-idle}")
private int maxIdle;
//最小空闲连接
@Value("${spring.redis.jedis.pool.min-idle}")
private int minIdle;
@Bean
public JedisPool redisPoolFactory(){
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
//注意值的转变
jedisPoolConfig.setMaxWaitMillis(Long.parseLong(maxWaitMillis.substring( 0,maxWaitMillis.length()-2)));
//注意属性名
jedisPoolConfig.setMaxTotal(maxTotal);
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMinIdle(minIdle);
JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, Integer.parseInt(timeout.substring(0, timeout.length() - 2)), password);
return jedisPool;
}
}
(3)编写启动类和测试类
- 启动类:
@SpringBootApplication
public class Start {
public static void main(String[] args) {
SpringApplication.run(Start.class,args);
}
}
- 测试类:
@SpringBootTest
public class RedisTest {
@Resource//注入
private JedisPool jedisPool;
private Jedis jedis=null;
@Test
public void test01(){
Jedis jedis=jedisPool.getResource();
System.out.println(jedis.ping());
}
}
注意此处的测试类与启动类的目录需要一致,否则需要加注解@SpringBootTest(classes = Start.class)指定启动类,否则报错
(4)测试常用数据结构:String,Hash,List
- String 数据类型
@SpringBootTest
public class RedisTest {
@Resource
private JedisPool jedisPool;
private Jedis jedis=null;
@Test
public void StringTest(){
Jedis jedis=jedisPool.getResource();
//添加
System.out.println(jedis.set("添加", "添加成功"));
//查询
System.out.println(jedis.keys("*"));
System.out.println(jedis.get("添加"));
System.out.println(jedis.get("id"));
//自增自减
System.out.println(jedis.incr("id"));
System.out.println(jedis.decr("id"));
//定时
jedis.setex("time",20,"开始计时");
System.out.println(jedis.ttl("time"));
jedis.expire("添加",100);
//删除
System.out.println(jedis.del("a"));
jedis.close();
}
}
- Hash 数据类型
@SpringBootTest
public class RedisTest {
@Resource
private JedisPool jedisPool;
private Jedis jedis=null;
@Test
public void HashTest(){
Jedis jedis=jedisPool.getResource();
Map<String,String> map=new HashMap<>();
map.put("demo1","001");
map.put("id","12");
map.put("phone","1111");
//添加
System.out.println(jedis.hset("hash1", map));
//查询
System.out.println(jedis.hget("hash1", "id"));
jedis.hgetAll("hash1").forEach((k,v)->{
System.out.println("key"+"----"+k+"----"+"v"+"----"+v);
});
//自增
System.out.println(jedis.hincrBy("hash1", "id", 10));
System.out.println(jedis.hget("hash1", "id"));
//位
System.out.println(jedis.setbit("admin", 001, true));
System.out.println(jedis.setbit("admin", 002, true));
System.out.println(jedis.setbit("admin", 003, true));
System.out.println(jedis.getbit("amdin", 003));
//删除hdel是删除某个字段,del是删除键
System.out.println(jedis.del("admin"));
//hexists检查是否存在
System.out.println(jedis.hexists("hash1", "id"));
jedis.close();
}
}
- List 集合类型
@Test
public void ListTest() {
Jedis jedis=jedisPool.getResource();
System.out.println(jedis.lpush("list1", "aa", "bb", "cc"));
System.out.println(jedis.rpush("list1", "dd"));
System.out.println(jedis.lrange("list1",0,-1));
}
2、Spring data redis–Java版客户端
① 入门(依赖✧测试)
- 引入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
</parent>
<!--set、get等方法免写,注解@Data-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- spring data redis 组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- commons-pool2 对象池依赖 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- web 组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- test 组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
- 创建测试类直接引入redisTemplate模板测试
@SpringBootTest(classes = Start.class)
public class LettuceTest {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void test1(){
redisTemplate.opsForValue().set("lettuce","demo");
System.out.println(redisTemplate.opsForValue().get("lettuce"));
}
}
通过客户端查看使用默认的模板,存入的数据进行了序列化,导致存入的是二进制内容
②常用方式⭐
(1)重写模板编写配置类RedisConfig.java
@Configuration
public class RedisConfig{
@Bean
public RedisTemplate<String,Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory){
RedisTemplate<String,Object> redisTemplate = new RedisTemplate<> ();
//为string类型key设置序列器
redisTemplate.setKeySerializer(new StringRedisSerializer());
//为string类型value设置序列器
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
//为hash类型key设置序列器
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
//为hash类型value设置序列器
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
}
(2)Application.yml 配置
spring:
redis:
# Redis服务器地址
host: 192.168.168.129
# Redis服务器端口
port: 6399
# Redis服务器端口
password: 123456
# Redis服务器端口
database: 0
# 连接超时时间
timeout: 10000ms
lettuce:
pool:
# 最大连接数,默认8
max-active: 1024
# 最大连接阻塞等待时间,单位毫秒,默认-1ms
max-wait: 10000ms
# 最大空闲连接,默认8
max-idle: 200
# 最小空闲连接,默认0
min-idle: 5
(3)编写User类(测试使用)
@Data
public class User implements Serializable {
private String name;
private String phone;
}
(4)测试
@SpringBootTest(classes = Start.class)
public class LettuceTest {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void test2(){
redisTemplate.opsForValue().set("lettuce","demo");
System.out.println(redisTemplate.opsForValue().get("lettuce"));
User user=new User();
user.setName("小王");
user.setPhone("1012");
redisTemplate.opsForValue().set("user",user);
System.out.println(redisTemplate.opsForValue().get("user"));
}
}
(5)常用数据结构测试
小细节:redis存储键值对形式 但String 和hash的区别在于:String存的格式:key:value hash存的格式:key:<key:value>
- String 类型
@SpringBootTest
public class LettuceTest1 {
@Autowired
private RedisTemplate<String,String> redisTemplate;
//valueOperations默认的需要redisTemplate作为参数,故在指定此注入
@Resource(name = "redisTemplate")
private ValueOperations<String,Object> valueOperations;//String的接口
//String测试
@Test
public void test(){
valueOperations.set("test001","test001");
System.out.println(valueOperations.get("test001"));
//批量增加
Map<String,Object> map=new HashMap<>();
map.put("demo1","100");
map.put("demo2","200");
valueOperations.multiSet(map);
valueOperations.multiGet(map.keySet()).forEach(value->{
System.out.println(value);
});
//自增
System.out.println(valueOperations.increment("id", 10));
//删除需要注入redisTemplate,因为接口valueOperations不提供删除
System.out.println(redisTemplate.delete("demo1"));
//设置过期时间TimeUnit.seconds时间单元
valueOperations.set("demo2","200",300L, TimeUnit.SECONDS);
//获取key的时间单元
System.out.println(redisTemplate.getExpire("demo2"));
//判断key
System.out.println(redisTemplate.hasKey("demo1"));
System.out.println(redisTemplate.type("demo2"));//STRING
}
@Resource(name = "redisTemplate"):这里可能会误报错,不用管
- Hash 类型
@SpringBootTest
public class LettuceTest1 {
@Autowired
private RedisTemplate<String,String> redisTemplate;
//hash
@Resource(name = "redisTemplate")
private HashOperations<String,String,Object> hashOperations;
//Hash
@Test
public void hash(){
//添加
Map<String,String> map=new HashMap<>();
map.put("one","111");
map.put("two","222");
hashOperations.putAll("map1",map);
//遍历
hashOperations.multiGet("map1", Arrays.asList("one","two")).forEach(v->{
System.out.println("value"+"----"+v);
});
//entries
hashOperations.entries("map1").forEach((k,v)->{
System.out.println("key"+"---"+k+"---"+"value"+"---"+v);
});
hashOperations.values("map1").forEach(v->{
System.out.println("value"+"--"+v);
});
//自增
hashOperations.put("map1","data",100);
System.out.println(hashOperations.increment("map1", "data", 10));
}
}
- List 类型
@SpringBootTest
public class LettuceTest1 {
@Autowired
private RedisTemplate<String,String> redisTemplate;
//list
@Resource(name = "redisTemplate")
private ListOperations<String,String> listOperations;
//列表list
@Test
public void list(){
System.out.println(listOperations.rightPushAll("java", "redis", "Spring", "SpringBoot"));
System.out.println(listOperations.range("java", 0, -1));//[redis, Spring, SpringBoot]
System.out.println(listOperations.index("java", 0));
listOperations.set("java",2,"linux");
System.out.println(listOperations.rightPop("java"));//linux
System.out.println(listOperations.range("java", 0, -1));//[redis, Spring]
}
}
二、读写分离✧主从复用⭐
1、读写分离
- 读写分离:为什么要读写分离?当一台redis负责读又负责写时,数据量一旦大,效率会大大折扣,而读写分离主要就是通过读写功能的划分,提高效率。
① 在linux中配置公告配置文件
创建三个文件夹/opt/redis/data,log,conf
mkdir data log conf //批量创建文件夹
复制redis.conf至conf文件中命名为公共配置redis-common.conf
cp /user/redis/conf/redis.conf /opt/redis/conf/redis-common.conf
修改redis-common.conf内容⭐
①注释掉bind 127.0.0.1
②protected-mode:no //关闭保护模式,修改为no
③注释公共配置端口port 6379
④修改为后台启动daemonize yes
⑤注释进程编号记录文件pidfile /var/run/redis_6379.pid
⑥注释公共配置日志文件logfile ""
⑦注释公共配置数据文件、修改数据文件路径
注释:dbfilename dump.rdb
修改:dir /opt/redis/data
⑧添加从服务器访问主服务器认证 masterauth root
⑨添加访问认证requirepass root
⑩注释公共配置追加文件appendfilename "appendonly.aof"
修改:appendonly no
⒒从服务器默认是只读不允许写操作(不用修改)slave-read-only yes
配置三个服务器的配置redis-6379.conf,redis-6380.conf,redis-6381.conf
#引用公共配置
include /opt/redis/conf/redis-common.conf
#进程编号记录文件
pidfile /var/run/redis-6379.pid
#进程端口号
port 6379
#日志记录文件
logfile "/opt/redis/log/redis-6379.log"
#数据记录文件
dbfilename dump-6379.rdb
#追加文件名称
appendfilename "appendonly-6379.aof"
#下面的配置无需在6379里配置
#备份服务器从属于6379推荐配置配局域网IP
slaveof 192.168.10.100 6379
此处3679作为主服务器,其他两个只需要该端口号即可最后slaveof是从服务器指向主服务器地址的
② 启动测试
[root@localhost bin]# ./redis-server /opt/redis/conf/redis-6379.conf
[root@localhost bin]# ./redis-server /opt/redis/conf/redis-6380.conf
[root@localhost bin]# ./redis-server /opt/redis/conf/redis-6381.conf
这里我们使用客户端连接,查看服务器状态,并在主服务添加,其余从服务器也会直接添加内容
2、主从复用
主要是对哨兵sentinel的配置:通过哨兵对主服务器的监听,每隔一段时间哨兵会对主服务器发送请求,主服务器在一定时间没有回应,一旦有两个以上的哨兵发现没有回应,则会进行从服务器选举,选出一个新的主服务器
①、配置
公共配置:sentinel-common.conf(从redis解压目录下复制sentinel.conf至/opt/redis/conf/)
cp sentinel.conf /opt/redis/conf/sentinel-common.conf
修改配置文件:
① 注释哨兵监听进程端口号port 26379
② 指示 Sentinel 去监视一个名为 master 的主服务器,这个主服务器的IP地址为 127.0.0.1,端
口号为6379,而将这个主服务器判断为失效至少需要1个(一般设置为2个)。 Sentinel 同意 (只要同意 Sentinel 的数量不达标,自动故障迁移就不会执行)
修改:sentinel monitor mymaster 192.168.10.100 6379 2
③ 设置master和slaves的密码
sentinel auth-pass mymaster root
④ Sentinel 认为服务器已经断线所需的毫秒数
sentinel down-after-milliseconds mymaster 10000
⑤ 若 sentinel 在该配置值内未能完成 failover 操作(即故障时master/slave自动切换),则认为本次 failover 失败。
sentinel failover-timeout mymaster 180000
⑥ 关闭保护模式,修改为no
protected-mode no
⑦ 修改为后台启动
daemonize yes
配置三个哨兵的配置文件sentinel-26379.conf,sentinel-26380.conf,sentinel-26381.conf
#引用公共配置
include /opt/redis/conf/sentinel-common.conf
#进程端口号
port 26379
#进程编号记录文件
pidfile /var/run/sentinel-26379.pid
#日志记录文件(为了方便查看日志,先注释掉,搭好环境后再打开)
logfile "/opt/redis/log/sentinel-26379.log"
复制 sentinel-26379.conf 的内容至 sentinel-26380.conf , sentinel-26381.conf 并且修改其内容,将26379替换即可。
②、启动测试
[root@localhost bin]# ./redis-sentinel /opt/redis/conf/sentinel-26379.conf
将主服务器杀死:
从服务器被选为主服务器