一、NoSQL相关知识点
1、NoSQL概念:
NoSQL(NoSQL = Not Only SQL ),泛指非关系型的数据库。能很好克服关系型数据库在高并发、大数据量环境下出现的问题。
2、关系型数据库
MySQL、SQLServer、Oracle…
关系型数据库:以关系(由行和列组成二维表)来建模的数据库。
3、NoSQL的分类
二、NoSQL的分类之一:Redis
1、Redis概念:
- Redis 是一个高性能的开源的、C语言写的Nosql(非关系型数据库),数据保存在内存中。
- redis是一个key-vlue类型Nosql!主要用途用来做缓存!
- 非关系型数据库严格上不是一种数据库,应该是一种数据结构化存储方法的集合。
- 数据结构:数组,list,set,map,tree等等
- redis给我们提供了一堆方法,调用特定方法就能把数据保存为特定数据结构。
2、Redis特点(优势)
- 数据存储:
数据保存在内存中,存取速度快,并发能力强,并且还能不定期持久化到硬盘。 - value类型:
相较于memcached支持Value更多,包括string(字符串)、list(链表)、set(集合)、 zset(sorted set --有序集合)和hash(哈希类型)。 - 客户端支持:
支持多种客户端-跨语言 - 超大并发支持
支持集群
3、Mysql、Memcached和Redis的比较
存储过期:存储数据时设置一个有效期,时间到了就没了.
场景:订单,vip,短信验证码,游戏道具,优惠券,红包等等
4、Memcached和Redis的相同点和不同点?
- 相同点:
都是key-value类型Nosql,都存放数据到内存中,读写效率高,而且都支持存储过期. - 不同点:
redis相较于Memcached还支持持久化到磁盘,数据安全更高.
redis相较于Memcached支持value类型更多.
5、Redis的使用场景
- 中央缓存
Hibernte二级缓存,mybatis二级缓存,这些缓存默认都不支持在集群环境使用.redis中央缓存就OK. - 计数器应用
注册用户数,网站总浏览次数等等 - 实时防攻击系统
- 排行榜
总积分榜,今日积分榜,周积分,月积分,季度积分 - 设定有效期的应用
设定一个数据,到一定的时间失效。 自动解锁,购物券 - 自动去重应用
Redis 的 set 数据结构 - 队列
秒杀、抢购:可以把名额放到内存队列(redis),内存就能处理高并发访问。 - 消息订阅系统
Redis 的 Pub/Sub 系统可以构建实时的消息系统,比如QQ群消息。
三、Redis使用
1、安装Redis服务端
官方下载地址
中文网::redis.cn
2、Windows下安装和使用
- 绿色软件,不需要安装,直接使用
- 启动redis服务(带配置文件启动,和不带配置文件启动)
3、Linux下的安装和使用
1下载redis源码
wget http://download.redis.io/releases/redis-3.0.6.tar.gz
或者使用ftp上传redis-3.0.6.tar.gz
2安装redis
tar xf redis-3.0.6.tar.gz //解压
cd redis-3.0.6
//不需要配置参数 不需要执行./configure
make && make install//编译&&安装
3将redis设置为系统服务
cp (redis源码目录)utils/redis_init_script /etc/init.d/redis
vim /etc/init.d/redis //修改红框处的代码
4修改redis.conf配置文件
mkdir /etc/redis //创建/etc/redis目录
cp redis.conf /etc/redis/redis.conf
vim /etc/redis.conf
//将redis配置文件复制到redis
//设置为守护进程,以后台方式运行
使用service redis start命令启动redis服务.
5 将redis服务设置为开机启动
chkconfig –-add redis
chkconfig –level 35 redis on
四、Redis的操作
- 使用redis-cli 客户端操作redis和java操作Redis
- redis是一个key-value的Nosql,我们能操作就只有String类型key以及各种类型value.但是一定要注意我们添加的一般都是字符串,只是会组织为特定数据结构.
- set(key ,map,set)–>set(key ,1),set(key ,”2”)
1、redis-cli 客户端操作redis
- 先点击打卡Redis的服务端
- 再点击打开Redis的客户端,并进行一系列的操作
(1)对value为string类型的常用操作
set key value//将字符串值value关联到key
get key //返回key关联的字符串值
mset //同时设置一个或多个 key-value 对
mget //返回所有(一个或多个)给定 key 的值
incr key //将 key 中储存的数字值增1(key不存在,则初始化为0,再加1)
decr key //将 key 中储存的数字值减1(key不存在,则初始化为0,再减1)
incrBy key num//自增多少
decrBy key num//自减多少
(2)对key的常用操作
keys * //获取所有key列表
del key //删除key
expire key xx //设置key的过期时间(xx秒后过期)
ttl key //查看key的过期时间
select 0-15 选择库 默认16个数据库
flushall //清空整个redis服务器数据,所有的数据库全部清空
flushdb //清除当前库,redis默认有16个数据库,名称分别为0,1,2…15
(3)对List集合的常用操作
- Redis如何实现栈和队列:
都用list,控制一边进同一边出就是栈,一边进另一边出就是队列。
list集合可以看成是一个左右排列的队列(列表)
lpush key value //将一个或多个值 value 插入到列表 key 的表头(最左边)
rpush key value //将一个或多个值 value 插入到列表 key 的表尾(最右边)
lrange key start stop//返回列表 key 中指定区间内的元素,查询所有的stop为-1即可
注意理解上添加数据的顺序
lpop key //移除并返回列表 key 的头(最左边)元素。
rpop key //移除并返回列表 key 的尾(最右边)元素。
注意数据移除的顺序
lrem key count value//根据count值移除列表key中与参数 value 相等的元素count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count 。count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值。count = 0 : 移除表中所有与 value 相等的值。
lindex key index //返回列表 key 中,下标为 index 的元素
ltrim key start stop //对一个列表进行修剪
(4)对set集合的常用操作
- set集合是一个无序的不含重复值的队列。
sadd key member //将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略
srem key member//移除集合 key 中的一个或多个 member 元素,不存在的 member 元素会被忽略
smembers key //返回集合 key 中的所有成员。
(5)对SortedSet(有序集合)的操作(了解)
(6)对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 中,所有的键和值
我们将user:1(name:zhangsan,age:18,sex:nv)的信息保存在hash表.
(7)对事务的操作:弱事务(了解)
multi //标记一个事务块的开始。
exec //执行所有事务块内的命令。
name是string类型
discard //取消事务,放弃执行事务块内的所有命令。
Redis的事务在执行exec指令时,才批量执行操作,没有回滚操作
(8)订阅/发布(了解)
SUBSCRIBE channel [channel …] //订阅给定的一个或多个频道的信息。
PUBLISH channel message //将信息 message 发送到指定的频道 channel 。
- 新开一个客户端订阅tv频道
- 再此新开一个客户端,并发布nihao!消息到tv频道
- 此时第一个订阅tv频道的客户端可以收到nihao!消息
(9)设置密码(了解)
AUTH 123456 //输入密码进行认证
-
通过命令动态调整密码-临时设置
-
通过配置文件设置密码-长久设置
在配置文件redis.conf中增加一行代码
requirepass 123456
然后,重新启动服务端
鉴权
AUTH 123456 //输入密码进行认证
2、java操作Redis
原来mysql需要使用jdbc,现在需要redis的一个java客户端jedis,使用jedis这个java客户端操作redis数据库。
(1)简单配置–连接操作
- 先导入操作需要的jar包:简单配置和连接池操作
- 开启服务器
使用jedis客户端完成redis简单操作
//完成简单配置的添加数据操作
@Test
public void myTestSet() throws Exception{
//获取连接
Jedis jedis = new Jedis("172.20.10.13");
//添加数据
jedis.set("name","zhangsan" );
//关闭连接
jedis.close();
}
//完成简单配置的获取数据操作
@Test
public void myTestGet() throws Exception{
//获取连接
Jedis jedis = new Jedis("172.20.10.13");
//获取数据
System.out.println(jedis.get("name"));//打印出zhangsan
//关闭连接
jedis.close();
}
(2)连接池配置–连接池操作
通过jedis连接池,简单操作redis数据库
- 大体流程图
@Test
public void myTestPoolSet() throws Exception{
//连接池配置对象
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
//配置
jedisPoolConfig.setMaxTotal(20);//高峰时,最大连接数
jedisPoolConfig.setMaxIdle(10);//空闲时,最大连接数
jedisPoolConfig.setMaxWaitMillis(2*1000);//最大等待时间
jedisPoolConfig.setTestOnBorrow(true);//使用连接时,测试连接是否通畅
//获取连接池--有端口号,密码,时间,可以看源码JedisPool的构造方法中的参数
JedisPool jedisPool = new JedisPool(jedisPoolConfig,"172.20.10.13",6379,2*100,"123456");
//获取连接
Jedis jedis = jedisPool.getResource();
//添加数据
jedis.set("name", "lisi");
//获取数据
System.out.println(jedis.get("name"));//打印出lisi
//关闭连接
jedis.close();
}
(3)Jedis数据结构操作
和命令一样,jedis操作redis也可以操作key和各种类型value.
- 先进行工具类抽取。此处使用的是枚举的方式
public enum JedisUtils {
INSTANCE;
//连接池是单列
private static JedisPool pool=null;
//提供个静态代码块
static {
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(10);//最大连接数
config.setMaxIdle(5);//空闲的连接数
config.setMaxWaitMillis(2*1000);
config.setTestOnBorrow(true);
//创建一个jedis 连接redis服务器
pool = new JedisPool(config,"172.20.10.13",6379,2*1000,"123456");
}
//得到jedis对象
public Jedis getJedis(){
return pool.getResource();
}
//关闭jedis对象
public void closeJedis(Jedis jedis){
if(jedis!=null){
jedis.close();
}
}
}
- 使用工具类进行简单操作
@Test
public void myTestUtils() throws Exception{
//调用工具类得到jedis对象
Jedis jedis = JedisUtils.INSTANCE.getJedis();
//添加数据
jedis.set("name","wangwu" );
//获取数据
System.out.println(jedis.get("name"));//打印出wangwu
//关闭连接
jedis.close();
}
- 测试string类型的字符串操作
//对string类型的字符串进行操作
@Test
public void testJedisString() throws Exception{
//得到jedisUtils对象
Jedis jedis = JedisUtils.INSTANCE.getJedis();
jedis.flushDB();//清空当前数据库
System.out.println("name这个key是否存在:"+jedis.exists("name"));//false
jedis.set("name","张三");
System.out.println("name对应的值:"+jedis.get("name"));//张三
System.out.println("所有的key:"+jedis.keys("*"));//name
jedis.del("name");
System.out.println("所有的key:"+jedis.keys("*"));// []
//关闭连接
jedis.close();
}
append追加方法
@Test
public void testJedisStringOpt() throws Exception{
//得到jedisUtils对象
Jedis jedis = JedisUtils.INSTANCE.getJedis();
jedis.flushDB();//清空当前数据库
jedis.set("name","张三");//新增
jedis.set("name","李四");//修改
//set操作;会覆盖上一个数据
System.out.println("name对应的值:"+jedis.get("name"));//李四
//追加
jedis.append("name","王五");
System.out.println("name对应的值:"+jedis.get("name"));//李四王五
//关闭连接
jedis.close();
}
- 测试list数据操作
//list操作
@Test
public void testJedisListOpt() throws Exception{
//得到jedisUtils对象
Jedis jedis = JedisUtils.INSTANCE.getJedis();
jedis.flushDB();//清空当前数据库
//添加一些值到list里面
jedis.lpush("nums","15","13","66");
List<String> listNums = jedis.lrange("nums", 0, -1);
for (String listNum : listNums) {
System.out.println(listNum);//66 13 15
}
//排序 默认是升序
System.out.println(jedis.sort("nums"));//[13, 15, 66]
SortingParams sortingParams = new SortingParams();
sortingParams.desc();
System.out.println(jedis.sort("nums", sortingParams));//[66, 15, 13]
//字母排序
SortingParams sortingParams1 = new SortingParams();
sortingParams1.alpha();
// sortingParams.desc();
jedis.lpush("letters","a","f","c","e");
System.out.println(jedis.sort("letters", sortingParams1));//[a, c, e, f]
//关闭连接
jedis.close();
}
- set数据操作和hash操作
//set/hash部分操作
@Test
public void testJedisSetOpt() throws Exception{
//得到jedisUtils对象
Jedis jedis = JedisUtils.INSTANCE.getJedis();
jedis.flushDB();//清空当前数据库
//添加一些值到set里面
jedis.sadd("users","zs","ls","ww");
System.out.println(jedis.smembers("users"));//[ww, ls, zs]
jedis.hset("mp","name","cc");
System.out.println(jedis.hget("mp", "name"));//cc
jedis.close();
}
- 事务操作(了解)
//事务了解
@Test
public void testJedisTransactionOpt() throws Exception{
//得到jedisUtils对象
Jedis jedis = JedisUtils.INSTANCE.getJedis();
jedis.flushDB();//清空当前数据库
jedis.set("name","张三");
jedis.set("age","18");
//开启事务
Transaction multi = jedis.multi();
multi.incr("name");
multi.incr("age");
//执行事务
List<Object> exec = multi.exec();
//打印出:[redis.clients.jedis.exceptions.JedisDataException: redis.clients.jedis.exceptions.JedisDataException: ERR value is not an integer or out of range, 19]
System.out.println(exec);
//[张三, 19]
System.out.println(jedis.mget("name","age"));
jedis.close();
}
五、Redis持久化配置
1、简介
2、两种模式
RDB和AOF,可以通过修改redis.conf来进行配置.
(1)RDB模式
在指定的时间间隔内生成数据集的时间点快照,将内存中的数据存储到磁盘中
(2)AOF追加模式
appendonly yes //yes 开启,no 关闭
appendfsync always //每次有新命令时就执行一次fsync
appendfsync everysec //每秒 fsync 一次
appendfsync no //从不fsync(交给操作系统来处理,可能很久才执行一次fsync)
六、淘汰策略
淘汰一些数据,
volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的
allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
当redis存放的数据到达配置的最大内容后,会按照配置淘汰策略进行淘汰.