1 Redis 介绍
1.1 概述
- Redis是一个开源,先进的key-value存储,并用于构建高性能,可扩展的应用程序的完美解决方案。
- Redis数据库完全在内存中,使用磁盘仅用于持久性。
- 相比许多键值数据存储,Redis拥有一套较为丰富的数据类型。
- Redis可以将数据复制到任意数量的从服务器。
1.2 优势
- 异常快速:Redis的速度非常快,每秒能执行约11万集合,每秒约81000+条记录。
- 支持丰富的数据类型:Redis支持字符串、列表、集合、有序集合散列数据类型。
- 操作都是原子性:所有Redis操作是原子的,这保证了如果两个客户端同时访问的Redis服务器将获得更新后的值。
- 多功能实用工具:Redis是一个多实用的工具,可以在多个用例如缓存,消息,队列使用(Redis原生支持发布/订阅),任何短暂的数据,应用程序,如Web应用程序会话,网页命中计数等。
2 持久化
2.1 两种持久化方案 RDB和AOF
- RDB方式按照一定的时间间隔对数据集创建基于时间点的快照
- AOF方式记录Server收到的写操作到日志文件,在Server重启时通过回放这些写操作来重建数据集。 该方式类似于MySQL中基于语句格式的binlog。当日志变大时Redis可在后台重写日志。
2.2 AOF持久化配置
- 修改redis.config配置文件,找到appendonly。默认是appendonly no。改成appendonly yes
- 再找到appendfsync 。默认是 appendfsync everysec,appendfsync always
- 每次收到写命令就立即强制写入磁盘,最慢的,但是保证完全的持久化,不推荐使用appendfsync everysec
- 每秒钟强制写入磁盘一次,在性能和持久化方面做了很好的折中,推荐 appendfsync no
- 完全依赖os,性能最好,持久化没保证
2.3 RDB持久化配置
- 默认情况下,Redis保存数据集快照到磁盘,名为dump.rdb的二进制文件。可以设置让Redis在N秒内至少有M次数据集改动时保存数据集,或者你也可以手动调用SAVE或者BGSAVE命令。 例如,这个配置会让Redis在每个60秒内至少有1000次键改动时自动转储数据集到磁盘,save 60 1000
2 window 上安装redis
安装参考redis安装
2.1 测试安装
先在服务里停止 Redis
切换到 redis 安装的根目录,redis-server.exe redis.windows.conf
3 新建 redis maven 工程
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tzb.cn</groupId>
<artifactId>myredis</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.3.1</version>
</dependency>
</dependencies>
</project>
3.1 String
测试
3.1.1 案例1
package mystring;
import redis.clients.jedis.Jedis;
import java.util.List;
public class StringMain {
public static void main(String[] args) throws InterruptedException {
Jedis jedis=new Jedis("127.0.0.1",6379);
jedis.set("name","Mike");
System.out.println(jedis.get("name"));
/*
* 对 string 类型数据进行增减,前提是kv 对应的值是数字
* */
jedis.set("age","25");//给用户 Mike设置年龄
jedis.incr("age");//让 Mike的年龄增加一岁
System.out.println(jedis.get("age"));
/*
* 一次性插入多条数据
* */
jedis.mset("AAA","A-金樽清酒斗十千",
"BBB","B-玉盘珍羞直万钱",
"CCC","C-停杯投箸不能食",
"DDD","D-拔剑四顾心茫然");
List<String> results=jedis.mget("AAA","BBB","CCC","DDD");
for(String value:results){
System.out.println(value);
}
/*
* 设置字段的自动过期
* */
jedis.setex("tangshi",10,"直挂云帆济沧海"); // 这句古诗保持10秒钟
while(jedis.exists("tangshi")){
System.out.println("云帆济沧海");
Thread.sleep(1000);
}
System.out.println();
/*
* 对已经存在的字段设置过期时间
* */
jedis.set("tangshi","直挂云帆济沧海");
jedis.expire("tangshi",10);
while(jedis.exists("tangshi")){
System.out.println("云帆济沧海");
Thread.sleep(1000);
}
}
}
package mystring;
import redis.clients.jedis.Jedis;
import java.util.List;
public class StringMain {
public static void main(String[] args) throws InterruptedException {
Jedis jedis=new Jedis("127.0.0.1",6379);
jedis.set("name","Mike");
System.out.println(jedis.get("name"));
/*
* 对 string 类型数据进行增减,前提是kv 对应的值是数字
* */
jedis.set("age","25");//给用户 Mike设置年龄
jedis.incr("age");//让 Mike的年龄增加一岁
System.out.println(jedis.get("age"));
/*
* 一次性插入多条数据
* */
jedis.mset("AAA","A-金樽清酒斗十千",
"BBB","B-玉盘珍羞直万钱",
"CCC","C-停杯投箸不能食",
"DDD","D-拔剑四顾心茫然");
List<String> results=jedis.mget("AAA","BBB","CCC","DDD");
for(String value:results){
System.out.println(value);
}
/*
* 设置字段的自动过期
* */
jedis.setex("tangshi",10,"直挂云帆济沧海"); // 这句古诗保持10秒钟
while(jedis.exists("tangshi")){
System.out.println("云帆济沧海");
Thread.sleep(1000);
}
System.out.println();
/*
* 对已经存在的字段设置过期时间
* */
jedis.set("tangshi","直挂云帆济沧海");
jedis.expire("tangshi",10);
while(jedis.exists("tangshi")){
System.out.println("云帆济沧海");
Thread.sleep(1000);
}
}
}
D:\programs\Java\jdk1.8.0_181\bin\java.exe "-javaagent:D:\programs\JetBrains\IntelliJ IDEA 2018.2.4\lib\idea_rt.jar=55441:D:\programs\JetBrains\IntelliJ IDEA 2018.2.4\bin" -Dfile.encoding=UTF-8 -classpath D:\programs\Java\jdk1.8.0_181\jre\lib\charsets.jar;D:\programs\Java\jdk1.8.0_181\jre\lib\deploy.jar;D:\programs\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;D:\programs\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;D:\programs\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;D:\programs\Java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;D:\programs\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;D:\programs\Java\jdk1.8.0_181\jre\lib\ext\localedata.jar;D:\programs\Java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;D:\programs\Java\jdk1.8.0_181\jre\lib\ext\sunec.jar;D:\programs\Java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;D:\programs\Java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;D:\programs\Java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;D:\programs\Java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;D:\programs\Java\jdk1.8.0_181\jre\lib\javaws.jar;D:\programs\Java\jdk1.8.0_181\jre\lib\jce.jar;D:\programs\Java\jdk1.8.0_181\jre\lib\jfr.jar;D:\programs\Java\jdk1.8.0_181\jre\lib\jfxswt.jar;D:\programs\Java\jdk1.8.0_181\jre\lib\jsse.jar;D:\programs\Java\jdk1.8.0_181\jre\lib\management-agent.jar;D:\programs\Java\jdk1.8.0_181\jre\lib\plugin.jar;D:\programs\Java\jdk1.8.0_181\jre\lib\resources.jar;D:\programs\Java\jdk1.8.0_181\jre\lib\rt.jar;D:\Data\JavaProject\myredis\target\classes;C:\Users\tzb\.m2\repository\redis\clients\jedis\2.8.2\jedis-2.8.2.jar;C:\Users\tzb\.m2\repository\org\apache\commons\commons-pool2\2.4.2\commons-pool2-2.4.2.jar mystring.StringMain
Mike
26
A-金樽清酒斗十千
B-玉盘珍羞直万钱
C-停杯投箸不能食
D-拔剑四顾心茫然
云帆济沧海
云帆济沧海
云帆济沧海
云帆济沧海
云帆济沧海
云帆济沧海
云帆济沧海
云帆济沧海
云帆济沧海
云帆济沧海
云帆济沧海
云帆济沧海
云帆济沧海
云帆济沧海
云帆济沧海
云帆济沧海
云帆济沧海
云帆济沧海
云帆济沧海
云帆济沧海
Process finished with exit code 0
3.1.2 案例2
package mystring;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/*
* 计算三个擂台的比武次数
* */
public class Counter {
public static void main(String[] args){
/*
* 创建一个固定大小的线程池,3个擂台
* */
ExecutorService executorService = Executors.newFixedThreadPool(10);
/*
* 擂台1,2,3
* */
executorService.submit(new Arena("PK:totalNum:","少林寺"));
executorService.submit(new Arena("PK:totalNum:","武当派"));
executorService.submit(new Arena("PK:totalNum:","峨眉派"));
/*
* 报幕人员
* */
executorService.submit(new BaoMu("PK:totalNum"));
}
}
package mystring;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/*
* 计算三个擂台的比武次数
* */
public class Counter {
public static void main(String[] args){
/*
* 创建一个固定大小的线程池,3个擂台
* */
ExecutorService executorService = Executors.newFixedThreadPool(10);
/*
* 擂台1,2,3
* */
executorService.submit(new Arena("PK:totalNum:","少林寺"));
executorService.submit(new Arena("PK:totalNum:","武当派"));
executorService.submit(new Arena("PK:totalNum:","峨眉派"));
/*
* 报幕人员
* */
executorService.submit(new BaoMu("PK:totalNum"));
}
}
package mystring;
import redis.clients.jedis.Jedis;
import java.util.Random;
public class Arena implements Runnable {
private Random random = new Random();
private String redisKey;
private Jedis jedis;
private String arenaName;
public Arena(String redisKey, String arenaName) {
this.redisKey = redisKey;
this.arenaName = arenaName;
}
public void run() {
jedis = new Jedis("127.0.0.1", 6397);
String[] daxias = new String[]{
"郭靖", "黄蓉", "黄药师", "老顽童", "西毒", "北丐", "杨过", "张无忌",
"小龙女", "郭襄", "乔峰", "段誉", "东方不败", "周芷若", "逍遥子",
"慕容复"};
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
int p1 = random.nextInt(daxias.length);
int p2 = random.nextInt(daxias.length);
while (p1 == p2) { //如果是同一个人
p2 = random.nextInt(daxias.length);
}
System.out.println("在擂台"+arenaName+daxias[p1]+" VS "+daxias[p2]);
jedis.incr(redisKey);
}
}
}
package mystring;
import redis.clients.jedis.Jedis;
import java.util.Random;
public class Arena implements Runnable {
private Random random = new Random();
private String redisKey;
private Jedis jedis;
private String arenaName;
public Arena(String redisKey, String arenaName) {
this.redisKey = redisKey;
this.arenaName = arenaName;
}
public void run() {
jedis = new Jedis("127.0.0.1", 6397);
String[] daxias = new String[]{
"郭靖", "黄蓉", "黄药师", "老顽童", "西毒", "北丐", "杨过", "张无忌",
"小龙女", "郭襄", "乔峰", "段誉", "东方不败", "周芷若", "逍遥子",
"慕容复"};
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
int p1 = random.nextInt(daxias.length);
int p2 = random.nextInt(daxias.length);
while (p1 == p2) { //如果是同一个人
p2 = random.nextInt(daxias.length);
}
System.out.println("在擂台"+arenaName+daxias[p1]+" VS "+daxias[p2]);
jedis.incr(redisKey);
}
}
}
package mystring;
import redis.clients.jedis.Jedis;
public class BaoMu implements Runnable {
private Jedis jedis;
private String redisKey;
public BaoMu(String redisKey) {
this.redisKey = redisKey;
}
public void run() {
jedis=new Jedis("127.0.0.1",6379);
while(true){
try {
Thread.sleep(1000);
System.out.println("*** 当前比武次数 ***"+jedis.get(redisKey));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
package mystring;
import redis.clients.jedis.Jedis;
public class BaoMu implements Runnable {
private Jedis jedis;
private String redisKey;
public BaoMu(String redisKey) {
this.redisKey = redisKey;
}
public void run() {
jedis=new Jedis("127.0.0.1",6379);
while(true){
try {
Thread.sleep(1000);
System.out.println("*** 当前比武次数 ***"+jedis.get(redisKey));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
3.1.3 案例3
package mystring;
import com.google.gson.Gson;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import java.io.*;
public class PruductService {
@Test
public void saveProduct2Redis() throws Exception{
Person person =new Person("Mike",25);
Jedis jedis=new Jedis("127.0.0.1",6379);
//直接保存对象的toString方法,这种方式不反序列化对象
jedis.set("user:Mike:str",person.toString());
System.out.println(jedis.get("user:Mike:str"));
//保存序列化后的对象
jedis.set("user:Mike:obj".getBytes(),getBytesByProduct(person));
byte[] productBytes=jedis.get("user:Mike:obj".getBytes());
Person pByte=getProductByBytes(productBytes);
System.out.println(pByte.getName()+" "+pByte.getAge());
//保存 Json 化之后的对象
jedis.set("user:Mike:json",new Gson().toJson(person));
String personJson=jedis.get("user:Mike:json");
Person pjson=new Gson().fromJson(personJson,Person.class);
System.out.println(pjson.getName()+" "+pjson.getAge());
}
/*
* 从字节数组中读取对象
* */
public Person getProductByBytes(byte[] productBytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(productBytes);
ObjectInputStream objectInputStream=new ObjectInputStream(byteArrayInputStream);
return (Person)objectInputStream.readObject();
}
/*
*
* 把对象转换为 Byte 数组
* */
public byte[] getBytesByProduct(Person product) throws IOException {
ByteArrayOutputStream ba=new ByteArrayOutputStream();
ObjectOutputStream oos= new ObjectOutputStream(ba);
oos.writeObject(product);
oos.flush();
return ba.toByteArray();
}
}
package mystring;
import com.google.gson.Gson;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import java.io.*;
public class PruductService {
@Test
public void saveProduct2Redis() throws Exception{
Person person =new Person("Mike",25);
Jedis jedis=new Jedis("127.0.0.1",6379);
//直接保存对象的toString方法,这种方式不反序列化对象
jedis.set("user:Mike:str",person.toString());
System.out.println(jedis.get("user:Mike:str"));
//保存序列化后的对象
jedis.set("user:Mike:obj".getBytes(),getBytesByProduct(person));
byte[] productBytes=jedis.get("user:Mike:obj".getBytes());
Person pByte=getProductByBytes(productBytes);
System.out.println(pByte.getName()+" "+pByte.getAge());
//保存 Json 化之后的对象
jedis.set("user:Mike:json",new Gson().toJson(person));
String personJson=jedis.get("user:Mike:json");
Person pjson=new Gson().fromJson(personJson,Person.class);
System.out.println(pjson.getName()+" "+pjson.getAge());
}
/*
* 从字节数组中读取对象
* */
public Person getProductByBytes(byte[] productBytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(productBytes);
ObjectInputStream objectInputStream=new ObjectInputStream(byteArrayInputStream);
return (Person)objectInputStream.readObject();
}
/*
*
* 把对象转换为 Byte 数组
* */
public byte[] getBytesByProduct(Person product) throws IOException {
ByteArrayOutputStream ba=new ByteArrayOutputStream();
ObjectOutputStream oos= new ObjectOutputStream(ba);
oos.writeObject(product);
oos.flush();
return ba.toByteArray();
}
}