(一)NoSql
关系型数据库:指以关系(行和列组成的二维表)来建模的数据库。
NoSQL泛指非关系型数据库。非关系型数据库严格而言不是一种数据库,应该是一个数据结构化存储方法的集合。其中redis就是非关系型数据库。
- nosql分类:
redis是一个key-vlue类型Nosql!主要用途用来做缓存,查询速度非常快,因为是给予内存查询。
(二)初识Redis
-
特点
① 数据存储:数据保存在内存中,存取速度快,还能不定期持久化到硬盘中,保障数据的安全性
② Value类型:支持存储的value类型相对memcached更多,包括string(字符串)、list(链表)、set(集合)、 zset(sorted set --有序集合)和hash(哈希类型),很大程度补偿了memcached这类key/value存储的不足,在部分场合可以对关系数据库(如MySQL)起到很好的补充作用。
④ 客户端支持:提供了Java,C/C++,C#,PHP,JavaScript等客户端,使用很方便。
⑤超大并发支持:Redis支持集群(主从同步)。数据可以主服务器向任意数量从的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。(单点故障)
⑥ 支持订阅/发布(subscribe/publish)功能 QQ群 -
使用场景
① 中央缓存
② 计数器
③ 实时防攻击系统
④ 排行榜
⑤ 数据的有效期(购物券、优惠券、红包)
⑥ 使用set存值,可自动去重
⑦ 队列
⑧ 消息订阅 -
软件认识
-
常用指令
auth pwd;
set key value; //赋值
get key; //取值
mset k1 v1 k2 v2 … //批量添加
mget k1 k2 … //批量获取
incr key //加1
incrBy key step // 添加指定步长
decr key
decrBy key step
keys * ///获取所有的key
del key //删除指定key
flushdb //清空指定数据库
flushall //清空所有数据库
select index //通过索引选择数据库(0-15)
expire key xx //设置key的过期时间(xx秒后过期)
ttl key //查看key的过期时间
面试题:redis怎么实现栈和队列?
栈和队列都用list,控制一边进同一边出就是栈:
进和出同一个方向: Lpush pc 111 lpop pc
一边进另一边出就是队列:先进先出:FIFO
进和出的方向相反就ok:
Lpush pc 111 rpop pc
-
list集合
lpush key value //将一个或多个值 value 插入到列表 key 的表头(最左边)
rpush key value //将一个或多个值 value 插入到列表 key 的表尾(最右边)
lpop key //移除并返回列表 key 的头(最左边)元素。
rpop key //移除并返回列表 key 的尾(最右边)元素。
lrange key start stop //返回列表 key 中指定区间内的元素,查询所有的stop为-1即可
lrem key count value //根据count值移除列表key中与参数 value 相等的元素count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count 。count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值。count = 0 : 移除表中所有与 value 相等的值。
Count:正数负数决定移除的方向;
count:绝对值决定移除的数量
lindex key index //返回列表 key 中,下标为 index 的元素
ltrim key start stop //对一个列表进行修剪:只保留 start 和stop范围内的数据(闭区间) -
set集合
sadd key member //将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略
srem key member //移除集合 key 中的一个或多个 member 元素,不存在的 member 元素会被忽略
smembers key //返回集合 key 中的所有成员。
- 有序集合SortedSet
- hash 功能。
hset key name value//添加一个name=>value键值对到key这个hash类型
hget key name //获取hash类型的name键对应的值
hmset key name1 key1 name2 key2 //批量添加name=>value键值对到key这个hash类型
hmget key name1 name2//批量获取hash类型的键对应的值
hkeys //返回哈希表 key 中的所有键
hvals //返回哈希表 key 中的所有值
hgetall //返回哈希表 key 中,所有的键和值
(三)java代码操作Redis
- 连接-设置并获取值
@Test
public void test() throws Exception{
//1)创建连接
Jedis connection = new Jedis("127.0.0.1",6379);
connection.auth("root");
//2)使用连接进行操作
connection.set("name", "yhptest");
System.out.println(connection.get("name"));
//3)关闭连接
connection.close();
}
- 连接池-设置并获取值
@Test
public void testPool() throws Exception{
//如果创建一个对象后要做很多配置,还不如先创建它的配置对象进行配置后,再通过配置对象创建它.
//1 创建连接池配置对象
JedisPoolConfig config = new JedisPoolConfig();
//2 进行配置-四个配置
config.setMaxIdle(2);//最小连接(空闲最大连接)
config.setMaxTotal(10);//最大连接数
config.setMaxWaitMillis(2*1000);//最大等待时间
config.setTestOnBorrow(true);//获取连接时测试连接是否畅通
//3 通过配置对象创建连接池对象
JedisPool pool = new JedisPool(config,"127.0.0.1",6379,2*1000,"root");
//4 通过连接池获取连接
Jedis connection = pool.getResource();
// connection.auth()
//5 执行操作-设置值和获取值
connection.set("age", "25");
System.out.println(connection.get("age"));
//6 释放连接
connection.close();//释放和关闭公用一个方法,底层自动判断,如果是连接池环境则释放,否则关闭.
//7 摧毁连接(测试环境)-真实环境应该是在spring中配置的一个单例
pool.destroy();
}
- 工具类准备
public enum JedisUtil {
INSTANCE;
//连接池是单例....
private static JedisPool pool = null;
static {
//1 创建连接池配置对象
JedisPoolConfig config = new JedisPoolConfig();
//2 进行配置-四个配置
config.setMaxIdle(2);//最小连接(空闲最大连接)
config.setMaxTotal(10);//最大连接数
config.setMaxWaitMillis(2*1000);//最大等待时间
config.setTestOnBorrow(true);//获取连接时测试连接是否畅通
//3 通过配置对象创建连接池对象
pool = new JedisPool(config,"127.0.0.1",6379,2*1000,"root");
}
//获取连接
public Jedis getResource(){
return pool.getResource();
}
//释放连接
public void closeResource(Jedis jedis){
if (jedis != null) {
jedis.close();
}
}
}
- key值
@Test
public void testkey() throws Exception{
//获取连接
//清空所有数据-flushall
Jedis jedis = JedisUtil.INSTANCE.getResource();
System.out.println("清空数据:"+jedis.flushAll());
//执行的操作
System.out.println("判断key为name的值是否存在!"+jedis.exists("name"));//false
System.out.println("判断key为age的值是否存在!"+jedis.exists("age"));//false
System.out.println("判断key为sex的值是否存在!"+jedis.exists("sex"));//false
System.out.println("设置key为name值!"+jedis.set("name", "zs"));
System.out.println("设置key为age值!"+jedis.set("age", "18"));
System.out.println("设置key为sex值!"+jedis.set("sex", "nan"));
System.out.println("设置后再次判断key为name的值是否存在!"+jedis.exists("name"));//true
System.out.println("设置后获取key为name的值:"+jedis.get("name"));//zs
System.out.println("删除前判断key为sex的值是否存在!"+jedis.exists("sex")); //true
System.out.println("删除key为sex的值"+jedis.del("sex"));
System.out.println("删除后判断key为sex的值是否存在!"+jedis.exists("sex"));//false
System.out.println("获取所有的key:"); //name age
Set<String> keys = jedis.keys("*");
for (String key : keys) {
System.out.println(key+"--->"+jedis.get(key));
}
jedis.expire("name", 10);//设置过期时间
Thread.sleep(5000);
System.out.println(jedis.ttl("name"));//获取剩余过期时间
//释放连接
JedisUtil.INSTANCE.closeResource(jedis);
System.out.println("释放连接:");
}
- CRUD
``` @Test
public void testString1() throws Exception{
//获取连接
//清空所有数据-flushall
Jedis jedis = JedisUtil.INSTANCE.getResource();
System.out.println("清空数据:"+jedis.flushAll());
System.out.println("add....");
jedis.set("name", "ls");
jedis.set("age", "18");
System.out.println("del....");
System.out.println(jedis.get("name")); //ls
System.out.println(jedis.get("age")); //18
jedis.del("age");
System.out.println("update....");
jedis.set("name", "ww");
System.out.println(jedis.get("name"));//ww
System.out.println("append....");
jedis.append("name", "--->edit");
System.out.println("get....");
System.out.println(jedis.get("name"));//ww---->edit
System.out.println(jedis.get("age"));//nil
//释放连接
JedisUtil.INSTANCE.closeResource(jedis);
System.out.println("释放连接:");
}
- merger
@Test
public void testString2() throws Exception{
//获取连接
//清空所有数据-flushall
Jedis jedis = JedisUtil.INSTANCE.getResource();
System.out.println("清空数据:"+jedis.flushAll());
// jedis.mset()
// jedis.mget()
//jedis.del()
//释放连接
JedisUtil.INSTANCE.closeResource(jedis);
System.out.println("释放连接:");
}
- 高级操作-带过期时间,自增自减
@Test
public void testString3() throws Exception{
//获取连接
//清空所有数据-flushall
Jedis jedis = JedisUtil.INSTANCE.getResource();
System.out.println("清空数据:"+jedis.flushAll());
//jedis.setex(key,expire ,value )
//jedis.incr()
//jedis.incrBy(, )
//jedis.decr()
//释放连接
JedisUtil.INSTANCE.closeResource(jedis);
System.out.println("释放连接:");
}
(四)持久化配置
-
RDB模式
RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照,默认开启该模式.
如何关闭 rdb 模式:
save “”
#save 900 1 //至少在900秒的时间段内至少有一次改变存储同步一次
#save xxx
#save 60 10000 -
AOF追加模式
AOF 持久化记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集,默认关闭该模式。
如何开启aof模式:
appendonly yes //yes 开启,no 关闭
#appendfsync always //每次有新命令时就执行一次fsync
#这里我们启用 everysec
appendfsync everysec //每秒 fsync 一次
#appendfsync no //从不fsync(交给操作系统来处理,可能很久才执行一次fsync)
其它的参数请大家看redis.conf配置文件详解
面试题:redis是怎么存数据的
Redis是一个高性能的nosql,数据可以存在内存中,提高性能,同时也提供了持久化策略:
分为两种:
Rdb:保存数据文件
Aof:保存跟新的日志
如果redis.conf的文件中:配置appendonly yes ==>redis会保存更新日志,
如果配置了:save time count ==>满足这个策略的时候,会把数据记录到rdb文件中;
启动服务的时候:
先判断是否appendonly yes,如果是yes就加载aof文件,恢复数据;
如果是no,就看是否有rdb文件,有就加载恢复
应该吧aof策略打开,配合rdb策略:如果不知道就按照默认配置.
(五)淘汰策略
allkeys-lru : 淘汰最近最少使用的数据