============================开题:redis简介============================
2、 互联网时代背景下大机遇,什么要使用Nosql?
1) 当数据量的总大小一个机器放不下时。
2) 数据索引一个机器的内存放不下时。
3) 访问量(读写混合)一个实例放不下时。单机时代模型
详见:redis介绍
1.redis安装:下载压缩包,解压,然后cmd终端中进入redis安装根路径
1.1启动redis服务器:redis-server.exe 【redis.windowws.conf】--【】括号内可以不加
1.2(需要另打开一个cmd终端)redis客户端链接上数据库: redis-cli.exe -h 数据库服务IP地址 -p 端口 【-a password】
实例:redis-cli.exe -h 127.0.0.1 -p 6379
redis服务启动成功:
redis数据库链接成功:
=================================题外话=================================
redis的配置:配置:config set 配置名 配置值 —— 查看配置:config get 配置名
举例:
127.0.0.1:6379> config get loglevel
1) "loglevel"
2) "notice"
redis安全:设置密码后,客户端连接 redis 服务就需要密码验证,否则无法执行命令。
config set requirepass "pass"
config set requirepass "pass"
验证密码:
AUTH "pass"
======================
其中Redis默认配置文件中提供了三个条件:
save 900 1 (表示900s(15分钟)内有1个更改,redis服务器就存储到disk硬盘中)
save 300 10 (300s(5分钟)内有10个更改,redis服务器就存储到disk硬盘中)
save 60 10000 (60s内有10000个更改,redis服务器就存储到disk硬盘中)
redis的存储在内存中,所以读写很快。但却数据不安全!!的,如果在执行过程中断电,则内存中数据将会丢失!!
所以,redis配置save指令,指定时间内去存储进disk硬盘中。同时redis根目录下创建一个dump.rdb文件
每执行一次save指令,就更新一次(本地硬盘中redis根目录下的)dump.rdb文件.
1.save: 服务端做的硬盘存储
2.bgsave:该命令在后台客户端执行,做硬盘存储。
====>恢复数据
如果需要恢复数据,只需将备份文件 (dump.rdb) 移动到 redis 安装目录并启动服务即可。获取 redis 目录可以使用 CONFIG 命令,如下所示===========================================================================
2.Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。
Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。
string类型是Redis最基本的数据类型,一个key最大能存储512MB。
增加<==>读取 数据:
String类型: 增加一个:set Key名 value值 —— 取:get key名
增加多个:mset key1 value1 key2 value2 .............. —— 取:mget key1 key2 ...........
127.0.0.1:6379> mset "s1" "1" "s2" "2" "s3" "3"
OK
127.0.0.1:6379> mget s1 s2 s3
1) "1"
2) "2"
3) "3"
====>拓展指令:incr -- 加1操作
举例:s1:0 —— incr s1 之后 ——>s1:1
127.0.0.1:6379> set s1 0
OK
127.0.0.1:6379> get s1
"0"
127.0.0.1:6379> incr s1
(integer) 1
127.0.0.1:6379> get s1
"1"
127.0.0.1:6379>
hash(哈希)类型:增加一个:hset key名 value —— 取:hget key名
增加多个:hmset key名 value(字段 字段值)
—— 取一个:hget key名 字段值,取全部:hgetall key名
删除hash中某个字段值:hdel key名 字段名
给hash里某一个字段加上指定值:hincrby hash名 字段名 指定值
-- 例:hincyby userinfo age 10 (在原来age上追加+10)
举例:userInfo类的属性有:name,age,sex
127.0.0.1:6379> hmset userinfo name "tom" age 12 sex "man"
OK
127.0.0.1:6379> hget userinfo name
"tom"
127.0.0.1:6379> hgetall userinfo
1) "name"
2) "tom"
3) "age"
4) "12"
5) "sex"
6) "man"
删除hash中某一字段值:
127.0.0.1:6379> hgetall userinfo
1) "name"
2) "tom"
3) "age"
4) "12"
5) "sex"
6) "man"
127.0.0.1:6379> hdel userinfo sex
(integer) 1
127.0.0.1:6379>
127.0.0.1:6379> hgetall userinfo
1) "name"
2) "tom"
3) "age"
4) "12"
list(列表)类型:(取出时,按照进入时的逆序排列)增加逆序:
lpush key名 value —— 取:lrange key名 下标起始index(0开始) 下标结束index
(取出时,按照进入时的正序排列)增加:
rpush key名 value —— 取:lrange key名 下标起始index(0开始) 下标结束index
127.0.0.1:6379> lpush list1 1
(integer) 1
127.0.0.1:6379> lpush list1 2
(integer) 2
127.0.0.1:6379> lpush list1 3
(integer) 3
127.0.0.1:6379> lrange list1 0 2
1) "3"
2) "2"
3) "1"
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379> rpush list2 a
(integer) 1
127.0.0.1:6379> rpush list2 b
(integer) 2
127.0.0.1:6379> rpush list2 c
(integer) 3
127.0.0.1:6379> lrange list2 0 2
1) "a"
2) "b"
3) "c"
127.0.0.1:6379>
set(列表)类型:无序
增加一个:sadd key名 member名 —— 取:smembers key名
增加多个:sadd key名 member1名 member2名 member3名 ........... —— 取:smembers key名
(注意:sadd set1 aa bb cc aa bb,成员有重复时,已添加过的aa,bb自动不再添加!!!)
举例:
127.0.0.1:6379> sadd set1 aa bb cc dd aa bb
(integer) 4
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379> smembers set1
1) "aa"
2) "bb"
3) "cc"
4) "dd"
127.0.0.1:6379>
注意:以上实例中 aa,bb 添加了两次,但根据集合内元素的唯一性,第二次插入的元素将被忽略。
zset(sorted set:有序集合)Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
zset的成员是唯一的,但分数(score)却可以重复。
(比如一个学生的分数75分,这个学生不可能再有别的分数了,这个学生唯一的。
然而得75分的学生有好几个。所以分数:75分是可以重复)
zadd 命令:
增加一个:zadd key名 score分 成员名 —— 取:smembers key名
增加多个:zadd key名 (score1分 成员1名) (score2分 成员2名) (score3分 成员3名) ...........
—— 第1种取:zrangebyscore stuscore 0 100 (这个理的0-100指的是分数score,50分,60分....)
—— 第2种取:zrange stuscore 0 2 【withscores--指结果带上分数展示】(这个理的0-2指的是下标index,从0开始....)
注意:并且zset取出时是有排序的。
增加时:stu1 60分,stu2 50分,stu3 90分,取出时顺序:stu2 50分,stu1 60分,stu3 90分
127.0.0.1:6379> zadd stuscore 60 stu1
(integer) 1
127.0.0.1:6379> zadd stuscore 50 stu2
(integer) 1
127.0.0.1:6379> zadd stuscore 90 stu3
(integer) 1
127.0.0.1:6379> zrangebyscore stuscore 0 100
1) "stu2"
2) "stu1"
3) "stu3"
127.0.0.1:6379> zrange stuscore 0 2
1) "stu2"
2) "stu1"
3) "stu3"
127.0.0.1:6379> zrange stuscore 0 2 withscores
1) "stu2"
2) "50"
3) "stu1"
4) "60"
5) "stu3"
6) "90"
127.0.0.1:6379> zadd stuscore 80 stu4 75 stu5 88 stu6
(integer) 3
===========================================================================
指令集锦:
删除key: del key名
验证是否存在指定key:exists key名(返回:1--存在 0--不存在)
获取当前所有的key名 :key * ,
获取当前所有的good开头的key名 :key good* ,
取hash中key 的所有字段名/字段值:hkeys key名 / hvals key名
127.0.0.1:6379> hkeys user
1) "name"
2) "age"
127.0.0.1:6379> hvals user
1) "tom"
2) "12"
incr --- 加1操作(递增1)
decr --- 减1操作(递减1)
append key名 “字符b”-- 在key名的value后面拼接上字符b
move key 例子:1【0......16】 ---- 把key名的键值对 移动到 1库,2库,3库.....等(如移入的库有同名key则不移动)
flushdb -- 清空当前库里所有键值对!
=====================================
3.redis终端中指令学习参见:
http://www.runoob.com/redis/redis-keys.html
更多命令请参考:https://redis.io/commands
4.redis的事务执行(命令模板:1.multi开启事务 2................一系列指令操作 3.exec开始执行该事务 )
以下是一个事务的例子, 它先以 MULTI 开始一个事务, 然后将多个命令入队到事务中, 最后由 EXEC 命令触发事务, 一并执行事务中的所有命令:
(收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行)
redis 127.0.0.1:6379> MULTI
OK
redis 127.0.0.1:6379> SET book-name "Mastering C++ in 21 days"
QUEUED
redis 127.0.0.1:6379> GET book-name
QUEUED
redis 127.0.0.1:6379> SADD tag "C++" "Programming" "Mastering Series"
QUEUED
redis 127.0.0.1:6379> SMEMBERS tag
QUEUED
redis 127.0.0.1:6379> EXEC
1) OK
2) "Mastering C++ in 21 days"
3) (integer) 3
4) 1) "Mastering Series"
2) "C++"
3) "Programming"
注意:Redis 事务的执行并
不是原子性的。(要么一起成功,要么一起失败 的操作叫
原子性操作。)
Redis 事务执行中,某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。
5.Java使用Redis:
package controller;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import redis.clients.jedis.Jedis;
public class TestConnetRedis {
public static void main(String[] args) {
//连接本地的 Redis服务
//写法一:Jedis jedis = new Jedis("localhost");
//写法二:
Jedis jedis = new Jedis("127.0.0.1", 6379);
//若设置了密码,则需验证密码
jedis.auth("pass");
System.out.println("连接成功");
//查看服务是否运行
System.out.println("服务正在运行: "+jedis.ping());
//<=======================至此,java链接redis数据库成功======================>
System.out.println("<=============至此,java链接redis数据库成功============>");
/**
* 开始应用redis数据库:
*/
//Java应用Redis的 String类型(字符串) 实例
javaUseRedisByString(jedis);
//Java应用Redis的 Hash类型(hash) 实例
javaUseRedisByHash(jedis);
//Java应用Redis的 List(列表) 实例
javaUseRedisByList(jedis);
//Java应用Redis的 Set类型(set) 实例
javaUseRedisBySet(jedis);
//Java应用Redis的 all Keys 实例
javaUseRedisGetKeys(jedis);
}
/**
* Java应用Redis的 String类型(字符串) 实例
*/
public static void javaUseRedisByString(Jedis jedis) {
//设置 redis 字符串数据===>对应cmd终端中指令:set str1(key名) "111"(value名)
jedis.set("str1", "111");
jedis.set("str2", "222");
jedis.set("str3", "333");
//获取存储的数据并输出===>对应cmd终端中指令:get str1(key名)
System.out.println("redis 存储的字符串str1为: "+ jedis.get("str1"));
System.out.println("redis 存储的字符串str2为: "+ jedis.get("str2"));
System.out.println("redis 存储的字符串str3为: "+ jedis.get("str3"));
}
/**
* Java应用Redis的 Hash类型(hash) 实例
*/
private static void javaUseRedisByHash(Jedis jedis) {
//设置 redis hash数据===>对应cmd终端中指令:hset user(key名) "name" "tom"(value名)
jedis.hset("user", "name", "tom");
jedis.hset("user", "age","12");
jedis.hset("user", "sex","boy");
//获取存储的数据并输出===>对应cmd终端中指令:hgetall user(key名) 或者:hget user(key名) name字段名
System.out.println("redis 存储的hash数据全部得出hgetall:user为: "+ jedis.hgetAll("user"));
/*打印:redis 存储的hash数据全部得出hgetall:user为: {sex=boy, age=12, name=tom}*/
System.out.println("redis 存储的hash数据:user的name为: "+ jedis.hget("user", "name"));
System.out.println("redis 存储的hash数据:user的age为: "+ jedis.hget("user", "age"));
System.out.println("redis 存储的hash数据:user的sex为: "+ jedis.hget("user", "sex"));
//====hmset一次增加多个字段======================================>
System.out.println("====hmset一次增加多个字段======================================>");
//设置 redis hash数据===>对应cmd终端中指令:hset user(key名) value:(name "tom" age 12 sex "boy")
Map<String, String> hashmap = new HashMap<String, String>();
hashmap.put("name","Lucy");
hashmap.put("age","13");
hashmap.put("sex","girl");
jedis.hmset("user2", hashmap);
//获取存储的数据并输出===>对应cmd终端中指令:hgetall user(key名) 或者:hget user(key名) name字段名
System.out.println("redis 存储的hash数据全部得出hgetall:user2为: "+ jedis.hgetAll("user2"));
/*打印:redis 存储的hash数据全部得出hgetall:user2为: {sex=girl, age=13, name=Lucy}*/
List<String> rsmap = jedis.hmget("user", "name", "age", "sex");
System.out.println("redis 存储的hash数据全部得出hmget:user2为: "+rsmap);
/*打印:redis 存储的hash数据全部得出hmget:user2为: [tom, 12, boy]*/
}
/**
* Java应用Redis的 List(列表) 实例
*/
public static void javaUseRedisByList(Jedis jedis) {
System.out.println("====逆序(先进后出)排序:====================================>");
//存储数据到列表中===>对应cmd终端中指令:lpush llist1(key名) "1"(value名)
jedis.lpush("llist1", "1");
jedis.lpush("llist1", "2");
jedis.lpush("llist1", "3");
//获取存储的数据并输出===>对应cmd终端中指令:lrange llist1(key名)
List<String> llist1 = jedis.lrange("llist1", 0, 2);//index范围:0,1,2全部取出
for(int i = 0 ;i < llist1.size();i++){
System.out.println("redis 列表项llist1为: "+ llist1.get(i));
}
//====正序排序:====================================>
System.out.println("====正序(先进先出)排序:====================================>");
//存储数据到列表中===>对应cmd终端中指令:rpush rlist2(key名) "1"(value名)
jedis.rpush("rlist2", "a");
jedis.rpush("rlist2", "b");
jedis.rpush("rlist2", "c");
//获取存储的数据并输出===>对应cmd终端中指令:lrange rlist2(key名)
List<String> rlist2 = jedis.lrange("rlist2", 0, 2);//index范围:0,1,2全部取出
for(int i = 0 ;i < rlist2.size();i++){
System.out.println("redis 列表项rlist2为: "+ rlist2.get(i));
}
}
/**
* Java应用Redis的 Set类型(set) 实例
*/
private static void javaUseRedisBySet(Jedis jedis) {
//设置 redis set数据===>对应cmd终端中指令:sadd set1(key名) "s1"(value名)...."s3"(value3名)
jedis.sadd("set1", "s1","s2","s3");
//获取存储的数据并输出===>对应cmd终端中指令:smembers set1(key名)
System.out.println("redis 存储的set1为: "+ jedis.smembers("set1"));
/*打印无序:redis 存储的set1为: [s3, s2, s1]*/
}
/**
* Java应用Redis的 all Keys 实例
*/
public static void javaUseRedisGetKeys(Jedis jedis) {
// 获取数据并输出
Set<String> keys = jedis.keys("*");
Iterator<String> it=keys.iterator() ;
while(it.hasNext()){
String key = it.next();
System.out.println("redis key名为: "+key);
}
}
}
更为详尽的多种写法参见:Java中使用Jedis操作Redis
6.Redis连接池:
package com.test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public final class RedisUtil {
//Redis服务器IP
private static String ADDR = "192.168.0.100";
//Redis的端口号
private static int PORT = 6379;
//访问密码
private static String AUTH = "admin";
//可用连接实例的最大数目,默认值为8;
//如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
private static int MAX_ACTIVE = 1024;
//控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
private static int MAX_IDLE = 200;
//等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;
private static int MAX_WAIT = 10000;
private static int TIMEOUT = 10000;
//在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
private static boolean TEST_ON_BORROW = true;
private static JedisPool jedisPool = null;
/**
* 初始化Redis连接池
*/
static {
try {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxActive(MAX_ACTIVE);
config.setMaxIdle(MAX_IDLE);
config.setMaxWait(MAX_WAIT);
config.setTestOnBorrow(TEST_ON_BORROW);
jedisPool = new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取Jedis实例
* @return
*/
public synchronized static Jedis getJedis() {
try {
if (jedisPool != null) {
Jedis resource = jedisPool.getResource();
return resource;
} else {
return null;
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 释放jedis资源
* @param jedis
*/
public static void returnResource(final Jedis jedis) {
if (jedis != null) {
jedisPool.returnResource(jedis);
}
}
}