1.NoSql 1.1什么是NoSql NoSql是为了解决高并发、高可扩展、高可用以及高写入而产生的数据库解决方案。 NoSql就是Not Only sql。Nosql是非关系型数据库,它是关系型数据库的良好补充,而不能替代关系型数据库。 1.2Nosql数据库分类(了解) a.键值(Key-Value)存储数据库 相关产品: Tokyo Cabinet/Tyrant、Redis、Voldemort、Berkeley DB 典型应用:内容缓存,主要用于处理大量数据的高访问负载。 数据模型:一系列键值对 优势:快速查询 劣势:存储的数据缺少结构化
b.列存储数据库 相关产品:Cassandra, HBase, Riak 典型应用:分布式的文件系统 数据模型:以列簇式存储,将同一列数据存在一起 (列族,可以简单理解为schema,可以在列族中添加很多的列) 优势:查找速度快,可扩展性强,更容易进行分布式扩展 劣势:功能相对局限
c.文档型数据库 相关产品:CouchDB、MongoDB 典型应用:Web应用(与Key-Value类似,Value是结构化的) 数据模型: 一系列键值对 优势:数据结构要求不严格 劣势:查询性能不高,而且缺乏统一的查询语法
d.图形(Graph)数据库 相关数据库:Neo4J、InfoGrid、Infinite Graph 典型应用:社交网络 数据模型:图结构 优势:利用图结构相关算法。 劣势:需要对整个图做计算才能得出结果,不容易做分布式的集群方案。 2.什么是redis Redis是用C语言开发的高性能的键值对存储的Nosql数据库。 redis是一个内存nosql数据库 redis中也是存储key-value形式的数据 redis中的key-value相比hbase等数据库来说,redis的value比较强大,它的value可以不仅仅是一个byte[] redis的value可以有结构:可以是一个list,也可以是一个hash,也可以是set… Redis存储的数据类型有五种:字符(string)、散列(hash)、列表(list)、集合(set)、有序集合(sorted set) 所以redis经常被称作为:数据结构服务器 3.redis的应用场景 缓存(数据查询、短连接、新闻内容、商品内容等等。(最多使用) 分布式集群架构中的session分离。 聊天室的在线好友列表。 任务队列.(秒杀、抢购、12306等等) 应用排行榜。 网站访问统计。 4.redis的安装 1.配置yum源,最后使用外网的源。 cd /etc/yum.repos.d/ mv CentOS-Base.repo.bak CentOS-Base.repo mv CentOS-Media.repo CentOS-Media.repo.bak yum clean all 2.上传Redis按照包并解压 yum install -y gcc
1.下载redis5的稳定版本,下载地址http://download.redis.io/releases/redis-5.0.9.tar.gz 2.上传redis-5.0.9.tar.gz到Linux服务器 3.解压redis源码包 tar -zxvf redis-5.0.9.tar.gz -C /usr/local/src/ 4.进入到源码包中,编译并安装redis cd /usr/local/src/redis-5.0.9/ make && make install 5.报错,缺少依赖的包 commond not found 6.配置本地YUM源并安装redis依赖的rpm包 yum -y install gcc 7.编译并安装 make && make install 8.报错,原因是没有安装jemalloc内存分配器,可以安装jemalloc或直接输入 make MALLOC=libc && make install(报error) 9.重新编译安装 make MALLOC=libc && make install 10.在/usr/local/下创建一个redis目录,然后拷贝redis自带的配置文件redis.conf到/usr/local/redis mkdir /usr/local/redis cp /usr/local/src/redis-5.0.9/redis.conf /usr/local/redis a. bind 172.16.200.103 127.0.0.1 b. daemonize yes #redis后台运行 c. requirepass 123456 #指定redis的密码 d. dir /data/redis #redis数据存储的位置 appendonly yes #开启aof日志,它会每次写操作都记录一条日志 11.启动redis节点 cd /usr/local/redis redis-server redis.conf 12.查看redis进程状态 ps -ef | grep redis(redis-server 6379) 13.使用命令登录: redis-cli -h 172.16.200.103 -p 6379 验证密码 auth 123456 5.redis的数据类型 1.Redis中存储数据是通过key-value存储的,对于value的类型有以下几种: 字符串 Map<String, String> Hash类型 Map<String, Map<String, String>> List Map<String, List> Set Map<String, HasSet> SortedSet(zset) Map<String, TreeSet> 在redis中的命令语句中,命令是忽略大小写的,而key是不忽略大小写的。 2.String数据类型操作 127.0.0.1:6379> set name zhangsan OK 127.0.0.1:6379> keys *
“name” 127.0.0.1:6379> get name “zhangsan” 127.0.0.1:6379> set age 18 OK 127.0.0.1:6379> get age “18” 自增 incr 自减 decr 127.0.0.1:6379> incr age (integer) 19 127.0.0.1:6379> incr name (error) ERR value is not an integer or out of range 自增指定数值(自增的步长) incrby decrby 127.0.0.1:6379>incrby age 2 (integer) 21 127.0.0.1:6379> del name (integer) 1 127.0.0.1:6379> del xxx (integer) 0 同时设置 获取多个键值 语法: MSET key value [key value …] MGET key [key …] 127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 OK 127.0.0.1:6379> get k1 “v1” 127.0.0.1:6379> mget k1 k2 k3“v1”“v2” 3)”v3” STRLEN命令返回键值的长度,如果键不存在则返回0。 语法:STRLEN key 127.0.0.1:6379> strlen str (integer) 0 127.0.0.1:6379> set str hello OK 127.0.0.1:6379> strlen str (integer) 5 适用场景 自增主键: 商品编号、订单号采用string的递增数字特性生成。 定义商品编号key:items:id 192.168.101.3:7003> INCR items:id (integer) 2 192.168.101.3:7003> INCR items:id (integer) 3 3.Hash hash叫散列类型,它提供了字段和字段值的映射。字段值只能是字符串类型,不支持散列类型、集合类型等其它类型。 3.1命令 赋值取值: hset hget 127.0.0.1:6379> hset hash1 age 20 (integer) 1 127.0.0.1:6379> hget hash1 age “20” 删除value中的key 127.0.0.1:6379> hdel hash1 age (integer) 1 删除key 127.0.0.1:6379> del hash1 (integer) 0 增加数字 127.0.0.1:6379> hincrby hash1 age 2 (integer) 22 同时赋予多值,取多值 127.0.0.1:6379> hmset hash1 name zhangsan sex 1 OK 127.0.0.1:6379> hmget hash1 name sex age“zhangsan”“1”“30” 获取所有键值 127.0.0.1:6379> hgetall hash1“age”“30”“name”“zhangsan”“sex”“1” 判断字段是否存在 语法:HEXISTS key field 127.0.0.1:6379> hexists user age 查看user中是否有age字段 (integer) 1 127.0.0.1:6379> hexists user name 查看user中是否有name字段 (integer) 0 只获取keys或者values 语法:HKEYS key HVALS key 127.0.0.1:6379> hmset user age 20 name lisi OK 127.0.0.1:6379> hkeys user“age”“name” 127.0.0.1:6379> hvals user“20”“lisi” 获取长度 HLEN key 127.0.0.1:6379> hlen user (integer) 2 3.2适用场景 存储商品信息 商品字段 【商品id、商品名称、商品描述、商品库存、商品好评】 定义商品信息的key 商品1001的信息在 Redis中的key为:[items:1001] 存储商品信息 192.168.101.3:7003> HMSET items:1001 id 3 name apple price 999.9 OK 获取商品信息 192.168.101.3:7003> HGET items:1001 id “3” 192.168.101.3:7003> HGETALL items:1001“id”“3”“name”“apple”“price”“999.9” 4.1List Redis的list使用的是linkedlist,linkedlist有两种方式:队列、堆栈。 在linkedlist中的头插法 和尾插法 队列中的名称: 入栈 push,出栈(弹栈) pop 4.2命令 lpush : 插入到队首 rpush: 插入到队尾 127.0.0.1:6379> lpush list1 4 5 6 (integer) 6 127.0.0.1:6379> rpush list1 a b (integer) 10 -1 表示获取最后一个 127.0.0.1:6379> lrange list1 0 -1“6”“5”“4”“a”“b” 127.0.0.1:6379> lrange list1 1 3 弹出列表,则表示从列表中删除 127.0.0.1:6379> lpop list1 “6” 127.0.0.1:6379> lpop list1 “5” 获取列表长度 127.0.0.1:6379> llen list1 (integer) 8 4.2适用场景 商品评论列表 思路: 在Redis中创建商品评论列表 用户发布商品评论,将评论信息转成json存储到list中。 用户在页面查询评论列表,从redis中取出json数据展示到页面。 定义商品评论列表key: 商品编号为1001的商品评论key【items: comment:1001】 192.168.101.3:7001> LPUSH items:comment:1001 ‘{“id”:1,“name”:“商品不错,很好!!”,“date”:1430295077289}’ 5.Set List和set的区别: List是有序且可重复 Set是无序唯一。 5.1命令 赋值 取值 127.0.0.1:6379> sadd set1 1 2 2 3 3 4 5 (integer) 5 127.0.0.1:6379> smembers set1“1”“2”“3”“4”“5” 删除元素 127.0.0.1:6379> srem set1 3 (integer) 1 判断元素是否存在 127.0.0.1:6379> sismember set1 3 (integer) 0 127.0.0.1:6379> sismember set1 4 (integer) 1 0没有 1 有 5.2运算命令 在set中可以进行差集、交集、并集的运算 5.2.1差集 127.0.0.1:6379> sadd set1 1 2 3 (integer) 1 127.0.0.1:6379> sadd set2 2 3 4 (integer) 3 127.0.0.1:6379> sdiff set1 set2“1” 属于A并且不属于B的元素构成的集合。 5.2.2交集 属于A且属于B的元素构成的集合。 127.0.0.1:6379> sinter set1 set2“2”“3” 5.2.3并集 属于A或者属于B的元素构成的集合 127.0.0.1:6379> sunion set1 set2“1”“2”“3”“4” 6.sortedset(zset) 有序集合和set以及list的区别 Zset是唯一且有序的。 Zset是通过score 来进行排序的。 6.1基本操作 127.0.0.1:6379> zadd zset1 1 haha 3 hehe 2 heihei (integer) 3 实际存储在redis中的 数据顺序为:haha 、 heihei 、 hehe (通过分数升序排序) 127.0.0.1:6379> zrange zset1 0 1“haha”“heihei” 降序排序 127.0.0.1:6379> zrevrange zset1 0 1“hehe”“heihei” 127.0.0.1:6379> zrem zset1 haha (integer) 1 127.0.0.1:6379> zscore zset1 hehe “3” 升序,查看 元素及值 zrange zset1 0 1 withscores“haha”“1”“heihei”“2” 返回值是更改后的分数 增加某元素的分数,返回值是更改后的分数 语法:ZINCRBY key increment member 127.0.0.1:6379> ZINCRBY scoreboard 4 lisi "101“ 获取元素的排名 升序,从小到大 语法:ZRANK key member 127.0.0.1:6379> ZRANK scoreboard lisi (integer) 0 降序,从大到小 语法:ZREVRANK key member 127.0.0.1:6379> ZREVRANK scoreboard zhangsan (integer) 1 6.2应用场景 需求:根据商品销售量对商品进行排行显示 思路:定义商品销售排行榜(sorted set集合),Key为items:sellsort,分数为商品销售量。 写入商品销售量: 商品编号1001的销量是9,商品编号1002的销量是10 127.0.0.1:6379> ZADD items:sellsort 9 1001 10 1002 商品编号1001的销量加1 127.0.0.1:6379> ZINCRBY items:sellsort 1 1001 商品销量前10名: 127.0.0.1:6379> ZRANGE items:sellsort 0 9 withscores 6.redis的客户端 java package cn._51doit; import redis.clients.jedis.Jedis; public class StringValueDemo { public static void main(String[] args) { //创建一个连接 Jedis jedis = new Jedis("192.168.133.3", 6379); //授权 jedis.auth("123456"); //选择使用的DB,默认使用0这个DB jedis.select(1); //插入数据 jedis.set("name", "laozhao"); jedis.set("age", "18"); jedis.setex("18611132889", 30, "8888888"); //取数据 String name = jedis.get("name"); String age1 = jedis.get("age"); System.out.println(name + " , " + age1); jedis.incrByFloat("age", 2.5); String age2 = jedis.get("age"); System.out.println(age2); jedis.close(); } }scala
import redis.clients.jedis.Jedis object StringValueDemo2 { def main(args: Array[String]): Unit = { val jedis = new Jedis("192.168.133.3", 6379) //授权 jedis.auth("123456") //选择DB jedis.select(0) //添加数据 jedis.set("aaa", "111") //自增 jedis.incr("aaa") val r: String = jedis.get("aaa") println(r) } } import java.util import redis.clients.jedis.Jedis object HashValueDemo1 { def main(args: Array[String]): Unit = { val jedis = new Jedis("192.168.133.3", 6379) //授权 jedis.auth("123456") //选择DB jedis.select(0) //jedis.hset("手机", "apple", "100") //jedis.hset("手机", "华为", "800") //jedis.hset("手机", "vivo", "500") //jedis.hset("电脑", "联想", "300") //jdis.hset("电脑", "小米", "800") //jedis.hset("电脑", "华为", "700") //jedis.hincrByFloat("手机", "华为", 119.9) val m1: util.Map[String, String] = jedis.hgetAll("手机") //导入隐式转换 import scala.collection.JavaConversions._ //使用scala的语法遍历java的集合了 for(t <- m1) { println(s"key: ${t._1} -> value: ${t._2}") } jedis.close() } } import java.util import redis.clients.jedis.{Jedis, ListPosition} object ListValueDemo1 { def main(args: Array[String]): Unit = { val jedis = new Jedis("192.168.133.3", 6379) //授权 jedis.auth("123456") //选择DB jedis.select(0) //添加数据 //jedis.lpush("lst4", "1", "2", "3", "2", "3", "2") //jedis.rpush("lst4", "4", "5", "6") //从指定的位置插入数据 //jedis.linsert("lst2", ListPosition.AFTER, "4", "7") jedis.lrem("lst4", 3, "2") val list: util.List[String] = jedis.lrange("lst4", 0, -1) //导入隐式转换 import scala.collection.JavaConversions._ for (e <- list) { println(e) } } } import java.util import redis.clients.jedis.Jedis object SetValueDemo1 { def main(args: Array[String]): Unit = { val jedis = new Jedis("192.168.133.3", 6379) //授权 jedis.auth("123456") //选择DB jedis.select(0) //添加数据 jedis.sadd("s1", "1", "2", "3", "3", "4") jedis.sadd("s2", "3", "4", "5", "6") val set: util.Set[String] = jedis.sdiff("s1", "s2") //导入隐式转换 import scala.collection.JavaConversions._ for (e <- set) { println(e) } } } import java.util import redis.clients.jedis.{Jedis, Tuple} object ZsetValueDemo { def main(args: Array[String]): Unit = { val jedis = new Jedis("192.168.133.3", 6379) //授权 jedis.auth("123456") //选择DB jedis.select(0) //zset是不能重复,但是可以排序的,按照得分进行排序 //jedis.zadd("z1", 5.5, "aaa") //jedis.zadd("z1", 6.5, "bbb") //jedis.zadd("z1", 3.5, "ccc") //jedis.zincrby("z1", 4.0, "ccc") //val set: util.Set[String] = jedis.zrevrange("z1", 0, 1) //同时取出得分 val tuples: util.Set[Tuple] = jedis.zrevrangeWithScores("z1", 0, 1) //导入隐式转换 import scala.collection.JavaConversions._ for (e <- tuples) { println(e.getElement + " , " + e.getScore) } } }