NoSQL方便扩展, 因为不像关系型数据库中的数据, 互相之间会有关联. 性能高, 而且数据类型多种多样, 不用提前设计. Redis代表Remote Dictionary Server. 可以用内存存储/持久化(rdb/aof), 效率高, 集成发布订阅系统, 有计时器和计数器. 有多重数据类型, 支持集群/事务.
传统的RDBMS: 有结构化组织, 有严格的一致性, 数据和关系都在单独的表中
NoSql: 没有固定查询语言, 采用键值对(Redis)/列(HBase)/文档存储(MongoDb), 图形数据库(Neo4J). CAP定理和BASE. 高性能/高可用/高可扩.
启动
我使用的brew安装的redis, 在路径/usr/local/etc/redis.conf下就是redis的配置文件. 将GENERAL下的后台运行改为yes: daemonize yes. 通过redis-server redis.conf由配置文件启动redis, redis-cli -p 6379连接redis服务. 通过set name/get name命令做测试. 在另外一个terminal用ps -ef|grep redis可以看到有两个redis服务, 用shutdown就可以断开服务, 用exit退出.
可以通过redis-benchmark工具测试redis性能.
基础知识
通过select可以选择数据库, flashdb清空当前数据库, flashall清空所有数据库, keys *查看所有key. redis默认16个数据库. redis是单线程的, 是基于内存的操作, 所以它的瓶颈在于急切内存和网络带宽, CPU不是瓶颈. 对于多线程来说, CPU会有上下文切换, 而对于内存没有上下文切换效更率好. 所以高性能服务期不应定时多线程的. 查看命令在官网文档查询即可.
数据类型
String
常用的有append, strlen等操作. 对于数字型的字符, 可以用incr/decr增减, incrby/decrby还能设置步长. getrange key1 0 3代表截取范围[0, 3]的4个字符, 同样也有setrange key1 1 x, 代表从编号1的字符开哦按时替换开始替换. mset k1 v1 k2 v2 k3 v3可以同时设置多个值. getset表示先get, 再set.
- setex: set with expire, eg.
setex key3 30 "hello" - setnx: set if not expire, 分布式锁中常常使用, eg.
getex key4 "hello" - ttl: time to live
模拟对象的getter/setter操作:
mset user:1:name zhangsan user:1:age 2
mget user:1:name user:1:age
List
lpush在头部添加值, rpush在尾部添加值, 用lrange list 0 -1可以查看所有值. 相对应的lpop/rpop就是移除头部/尾部元素的命令. 而lindex可以查看某个index的值, llen取list的长度.
lrem list 2 one: 移除list中2个值为one的元素ltrim list 1 2: 截取元素[1, 2]两个元素rpoplpush list1 list2: 将list1的最后元素, 移动到list2linsert list before "world" "hello": 在list的world前插入hello, 也通过after可以往后插
可以看出实际上list是一个链表.
Set
sadd添加元素, srem移除元素, 查看是否有元素sismember set1 hello, 查看所有元素smembers. scard获取set元素个数. sdiff取差集, sinter取交集, sunion取并集.
srandmember set1 2: 所以抽选2个元素spop: 随机删除元素smove set1 set2 "hello": 把set1中的hello移动到set2
Hash
hset hash1 field1 value设置值, hmset设置多个值, hmget获取多个值, hgetall获取所有值. hdel删除指定的key, hlen取hash大小, hexists判断key是否存在. hkeys/hvalsh获取所有的key/value.
hincrby hash1 field3 1: hash1的field3增加1hsetnx hash1 field3 hello: 有key field3则set, 没有则设置不成功
和String操作很类似, 只是key是用Hash实现的, 所以对象的存储用hash更加适合, 而String适合String本身的存储.
Zset
有序集合. 加三段数据:
zadd salary 2500 a
zadd salary 5000 b
zadd salary 500 c
从小到大显示全部zrangebyscore salary -inf +inf, 加上withscores代表附带成绩. eg. 显示工资小于2500的员工并升序: zrangebyscore salary -inf 2500, zrem移除, zcard获取有序集合中的个数. zrevrange salary 0 -1从大到小排序, zcount获取指定区间的成员数量.
其他
- Geospatial: 地理空间. 可以把经度纬度和名称添加到key中, eg.
GEOADD cars -115.17087 36.12306 my-car - Hyperloglog: 基数统计. 计算一个集合中不重复元素的值, 可能有误差.
事务
Redis单台命令保证原子性, 但是不保证原子性. Redis没也有隔离级别概念. 用multi开启事务, exec执行事务, discard取消事务. 如果在事务中用了错误的命令, 所有的命令都不会被执行. 但如果是运行时错误, 其他命令会执行, 只有运行错误的命令不执行, 比如incr k1, 而k1是一个字符.
乐观锁
回顾一下乐观的含义: 认为什么时候都不会出问题, 不会做什么都加锁. 而是在更新数据的时候判断一下, 在此期间室友该数据被人修改过. 所以需要获取version/比较version. 在redis就用watch去监视一个值, 如果当前事务修改了这个值, 那么另外一个事务就无法再次修改这个值. 通过unwatch停止监视.
Jedis
maven导入
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.6.1</version>
</dependency>
先new一个Jedis对象, 然后这个对象下的方法就是redis的所有指令.
public class TestPing {
public static void main(String[] args) {
//1.new Jedis对象
Jedis jedis = new Jedis("127.0.0.1", 6379);
//2.jedis的方法包含所有指令
System.out.println(jedis.ping());
}
}
comments powered by Disqus