javaWeb学习之redis和jedis
1.Redis的概述
概述:Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API,它和和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型),而且它是NoSQL技术阵营的一员。
Redis的特性
1.Redis与其他key-value缓存产品有以下三个特点
- Redis支持数据的持久化,可以将内存中的数据保存到磁盘中,重启的时候可以再次加载进行使用
- Redis不仅仅支持简单的key-value类型的数据,同时还提供了list,set,zset,hash等数据结构的存储
- Redis支持数据的备份,即master-slave模式的数据备份
2.Redis优势
- 性能极高:Redis能读的速度是11000次/s,写的速度是81000次/s
- 丰富的数据类型:Redis支持二进制案例的String,Lists,Hashes,Sets及Ordered Sets数据类型操作
- 原子性:Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性执行
- 丰富的特性:Redis还支持publish/subscribe,通知,key过期等等特性
2.Redis的下载和安装
Redis版本说明:
Redis原生只支持linux系统,Redis官方是不支持windows平台的,windows版本是微软自己建立的分支,基于官方的redis源码进行编译、发布、维护的,所以window平台上的redis版本都略低于官方版本
Reids下载
复制下载地址,然后到linux执行下载命令:
wget http://download.redis.io/releases/redis-6.0.6.tar.gz即可在linux下载
Reids安装
- 将redis-6.0.6.tar.gz进行解压
- tar-zxvf redis-6.0.6.tar.gz
- 进入redis-6.0.6目录
- cd redis-6.0.6
- 对redis进行编译
- make
- 安装到指定的目录
- 编译后进入src目录,执行命令make PREFIX=/usr/local/redis install(没有这个目录的话就先mkdir这个目录)
- 安装完成后,进入这个redis目录的bin目录,可以看到
- redis-server:redis服务器
- redis-cli redis:命令行客户端
- redis-benchmark redis: 性能测试工具
- redis-check-afo: AFO文件修复工具
- reids-check-rdb: RDB文件检索工具
redis的客户端测试
1.启动redis服务
我们需要将redis编译后的目录中的redis.conf文件copy到我们自己的redis目录中,这个redis.conf文件是redis的配置文件
复制redis配置文件的命令:cp redis.conf /usr/local/redis
复制好之后在我们的redis文件夹下执行:./bin/redis-server ./redis.conf 即可启动服务器(加载配置文件的启动)
2.客户端连接服务器
执行/usr/local/redis/bin/redis-cli进行连接本地的redis服务
3.连接成功后输入ping,返回Pong则已经连接成功了
3.Redis的使用
菜鸟教程:https://www.runoob.com/redis/redis-tutorial.html
4.redis的数据持久化介绍
概述:redis将内存存储和持久化存储相结合,即可提供数据访问的高效性,又可以保证数据存储的安全性
redis数据持久化机制介绍
1.RDB持久化:该机制是指在指定的时间间隔内将内存中的数据集快照写入磁盘(redis的默认持久化方式)
2.AOF(append only file)持久化:该机制将以日志的形式记录服务器所处理的每一个写操作,在redis服务器启动之初会读取该文件来重新构建数据库,以保证启动后数据库中的数据是完整的
3.同时应用AOF和RDB
4.无持久化:可通过配置的方式禁用redis服务器的持久化功能,这样我们就可以将redis视为一个功能加强版的memacached了(不推荐这么做)
redis数据持久化配置
1.RDB快照
缺省情况下,redis会将数据集的快照dump到dump.rdb文件中,此外,我们也可以通过配置文件来修改redis服务器dump快照的频率,在打开redis.conf文件后,搜索找到save,可以看到以下配置信息:
- save 900 1:在900秒后,如果至少有一个key发生变化,则dump内存快照
- save 300 10:在300秒后,如果至少有10个key发生变化,则dump内存快照
- save 60 10000:在60秒之后,如果至少有10000个key发生变化,则dump内存快照
关于dump.rbd文件存储的位置,它的设置在redis.conf文件中的“dir ./”, 这段配置指的是服务器启动时的当前路径,当前路径在哪里,这个dump.rdb文件就在哪里
2.AOF日志文件方式(持久化到appendonly.afo文件):
AOF日志持久化机制的开启:在redis.conf文件中将appendonly no改为appendonly yes
AOF同步方式的配置,在redis.conf文件中有三种同步方式:
- appendfsync always:每次有数据修改发生时就写入AOF文件
- appendfsync everysec:每秒钟同步一次,该策略为AOF的缺省策略
- appendfsync no:从不同步,高效但是数据不会被持久化
RDB与AOF的对比总结(抄摘自https://blog.csdn.net/m0_38110132/article/details/76906422)
RDB存在哪些优势呢?
1). 一旦采用该方式,那么你的整个Redis数据库将只包含一个文件,这对于文件备份而言是非常完美的。比如,你可能打算每个小时归档一次最近24小时的数据,同时还要每天归档一次最近30天的数据。通过这样的备份策略,一旦系统出现灾难性故障,我们可以非常容易的进行恢复。
2). 对于灾难恢复而言,RDB是非常不错的选择。因为我们可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上。
3). 性能最大化。对于Redis的服务进程而言,在开始持久化时,它唯一需要做的只是fork出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行IO操作了。
4). 相比于AOF机制,如果数据集很大,RDB的启动效率会更高。
RDB又存在哪些劣势呢?
1). 如果你想保证数据的高可用性,即最大限度的避免数据丢失,那么RDB将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。
2). 由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。
AOF的优势有哪些呢?
1). 该机制可以带来更高的数据安全性,即数据持久性。Redis中提供了3中同步策略,即每秒同步、每修改同步和不同步。事实上,每秒同步也是异步完成的,其效率也是非常高的,所差的是一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢失。而每修改同步,我们可以将其视为同步持久化,即每次发生的数据变化都会被立即记录到磁盘中。可以预见,这种方式在效率上是最低的。至于无同步,无需多言,我想大家都能正确的理解它。
2). 由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。然而如果我们本次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在Redis下一次启动之前,我们可以通过redis-check-aof工具来帮助我们解决数据一致性的问题。
3). 如果日志过大,Redis可以自动启用rewrite机制。即Redis以append模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会创建一个新的文件用于记录此期间有哪些修改命令被执行。因此在进行rewrite切换时可以更好的保证数据安全性。
4). AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上,我们也可以通过该文件完成数据的重建。
AOF的劣势有哪些呢?
1). 对于相同数量的数据集而言,AOF文件通常要大于RDB文件。RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。
2). 根据同步策略的不同,AOF在运行效率上往往会慢于RDB。总之,每秒同步策略的效率是比较高的,同步禁用策略的效率和RDB一样高效。
二者选择的标准,就是看系统是愿意牺牲一些性能,换取更高的缓存一致性(aof),还是愿意写操作频繁的时候,不启用备份来换取更高的性能,待手动运行save的时候,再做备份(rdb)。rdb这个就更有些 eventually consistent的意思了。不过生产环境其实更多都是二者结合使用的。
5.Jedis的介绍与入门
概述:想要通过java来操作redis就需要使用jedis
jedis的使用步骤:
1.导包
- jedis.jar包
2.入门代码
import redis.clients.jedis.Jedis;
public class MyFirstJedis {
public static void main(String[] args) {
//新建一个jedis,连接上的地址是192.168.75.142
Jedis jedis = new Jedis("192.168.75.142");
//设置连接的密码
jedis.auth("admin");
jedis.set("foo", "bar");
String value = jedis.get("foo");
System.out.println(value);
}
}
//输出bar即代表redis连接成功
注意:默认开启的redis服务端是不支持外部网络连接的,而且也没有设置密码,如果想要外部网络连接上这台服务器的redis服务,则需要先配置redis的redis.conf文件
- 配置允许外网访问:在redis.conf文件中找到bind 127.0.0.1,把bind 127.0.0.1注释掉
- 配置密码:在redis.conf文件中找到requirepass foobared,把他修改为requirepass admin(自己要设置的密码)
使用vi编辑器编辑redis.conf文件时可以使用:/你要查找的内容进行查找,如(:/bind 127.0.0.1)
jedis操作String类型
代码示例:
import java.util.List;
import redis.clients.jedis.Jedis;
public class MyFirstJedis {
public static void main(String[] args) {
//新建一个jedis,连接上的地址是192.168.75.142
Jedis jedis = new Jedis("192.168.75.142");
//设置连接的密码
jedis.auth("admin");
/* //set,get命令
jedis.set("foo", "bar");
String value = jedis.get("foo");
System.out.println(value);
//mset,mget命令
jedis.mset("username", "luyi", "age", "20");
List<String> list = jedis.mget("username", "age");
System.out.println(list);*/
//append setrange getrange
jedis.append("username", " is a boy");
System.out.println(jedis.get("username"));
jedis.setrange("username", 10, "gril");
System.out.println(jedis.get("username"));
System.out.println(jedis.getrange("username", 10, -1));
}
}
jedis操作list类型
代码示例:
import java.util.List;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.ListPosition;
public class MyFirstJedis {
public static void main(String[] args) {
//新建一个jedis,连接上的地址是192.168.75.142
Jedis jedis = new Jedis("192.168.75.142");
//设置连接的密码
jedis.auth("admin");
//lpush lrange
jedis.lpush("names", "luyi", "luer", "lusan");
List<String> list = jedis.lrange("names", 0, -1);
System.out.println(list);
//lset lindex
jedis.lset("names", 1, "huanger");
String value = jedis.lindex("names", 1);
System.out.println(value);
//linsert
jedis.linsert("names", ListPosition.BEFORE, "lusan", "huangsan");
List<String> list2 = jedis.lrange("names", 0, -1);
System.out.println(list2);
}
}
jedis操作hash类型
代码示例:
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import redis.clients.jedis.Jedis;
public class MyFirstJedis {
public static void main(String[] args) {
//新建一个jedis,连接上的地址是192.168.75.142
Jedis jedis = new Jedis("192.168.75.142");
//设置连接的密码
jedis.auth("admin");
/* //hset hget
jedis.hset("user", "username", "luyi");
String value = jedis.hget("user", "username");
System.out.println(value);*/
//hmset hmget
Map<String, String> hash = new HashMap<String, String>();
hash.put("username", "luyi");
hash.put("age", "19");
hash.put("sex", "male");
jedis.hmset("user", hash);
List<String> values = jedis.hmget("user", "username", "age", "sex");
System.out.println(values);
//hgetall hkeys hvals
Map<String, String> map = jedis.hgetAll("user");
for(String key:map.keySet()){
System.out.println(key + "---" + map.get(key));
}
Set<String> keys = jedis.hkeys("user");
System.out.println(keys);
List<String> list = jedis.hvals("user");
System.out.println(list);
}
}
jedis操作set类型
代码示例:
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import redis.clients.jedis.Jedis;
public class MyFirstJedis {
public static void main(String[] args) {
//新建一个jedis,连接上的地址是192.168.75.142
Jedis jedis = new Jedis("192.168.75.142");
//设置连接的密码
jedis.auth("admin");
/* //sadd smembers
jedis.sadd("language1", "c++", "c", "c#", "Java");
Set<String> set = jedis.smembers("language1");
System.out.println(set);*/
/* //srem
jedis.srem("language1","c++");
Set<String> set = jedis.smembers("language1");
System.out.println(set);*/
/* //差集sdiff
jedis.sadd("language1", "c++", "c", "c#", "Java");
jedis.sadd("language2", "c++", "python", "Ruby", "Java");
Set<String> sdiff = jedis.sdiff("language1", "language2");
System.out.println(sdiff);*/
/* //交集sdiff
jedis.sadd("language1", "c++", "c", "c#", "Java");
jedis.sadd("language2", "c++", "python", "Ruby", "Java");
Set<String> sinter = jedis.sinter("language1", "language2");
System.out.println(sinter);*/
//并集sunion
jedis.sadd("language1", "c++", "c", "c#", "Java");
jedis.sadd("language2", "c++", "python", "Ruby", "Java");
Set<String> sunion = jedis.sunion("language1", "language2");
System.out.println(sunion);
}
}
jedis操作sortedset类型
代码示例:
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Tuple;
public class MyFirstJedis {
public static void main(String[] args) {
//新建一个jedis,连接上的地址是192.168.75.142
Jedis jedis = new Jedis("192.168.75.142");
//设置连接的密码
jedis.auth("admin");
/* //zadd zrange zrangeByScore
Map<String, Double> map = new HashMap<String, Double>();
map.put("张三", 90.0);
map.put("李四", 80.0);
map.put("王五", 70.0);
map.put("赵六", 60.0);
jedis.zadd("zkey", map);
Set<String> set = jedis.zrange("zkey", 0, -1);
System.out.println(set);
Set<String> set2 = jedis.zrangeByScore("zkey", 70.0, 90.0);
System.out.println(set);
Set<Tuple> set3 = jedis.zrangeWithScores("zkey", 0, -1);
for(Tuple t : set3){
System.out.println(t.getScore() + "---" + t.getElement());
}*/
//zscore zrem
Map<String, Double> map2 = new HashMap<String, Double>();
map2.put("张三", 90.0);
map2.put("李四", 80.0);
map2.put("王五", 70.0);
map2.put("赵六", 60.0);
jedis.zadd("zkey", map2);
Double zcore = jedis.zscore("zkey", "张三");
System.out.println(zcore);
jedis.zrem("zkey", "赵六");
Set<String> set4 = jedis.zrange("zkey", 0, -1);
System.out.println(set4);
}
}
jedis中完成key的通用操作
代码示例:
package com.luyi.jedis;
import redis.clients.jedis.Jedis;
public class MyFirstJedis {
public static void main(String[] args) {
//新建一个jedis,连接上的地址是192.168.75.142
Jedis jedis = new Jedis("192.168.75.142");
//设置连接的密码
jedis.auth("admin");
/* //keys
Set<String> keys = jedis.keys("*");
System.out.println(keys);
//del
jedis.del("user");
Set<String> keys2 = jedis.keys("*");
System.out.println(keys2);*/
//关于key时间设置
jedis.expire("zkey", 100);//设置生命周期为200秒
long t = jedis.ttl("zkey");//获取生命周期值
System.out.println(t);
}
}
作者:卢一
出处:http://www.cnblogs.com/luyi001/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。