发表于: 2017-09-01 11:47:02
1 1585
今天做的事:
决定多花点时间好好学一学Redis,(据说外面很流行?)所以已经不管任务延不延期什么的了。
首先来点对Redis的简单介绍
明确一个概念,Redis,包括Memcache都是数据库,而且都是以key-value形式存储值的非关系型数据库。
我们可以看一下排行https://db-engines.com/en/ranking
可以看出来Memcache确实不行了,而Redis是上升趋势,为什么?说明Redis的性能好,所以大家都用(当然最屌的还是前三,毕竟业界大佬)
然后,我们看看Redis都能干什么。
不,我们先看看关系型数据库和非关系型数据库分别是干什么的,有啥区别啊
首先,名不一样!
引用一条回答
关系型数据库通过外键关联来建立表与表之间的关系,非关系型数据库通常指数据以对象的形式存储在数据库中,而对象之间的关系通过每个对象自身的属性来决定
非关系型数据库中,我们查询一条数据,结果出来一个对象,关系型数据库中,查询一条数据结果是一个数组。
另外,还有一些不是特别正经的答案,感觉有那么一点道理
用一种不精确但容易理解的方法来说:
关系型数据库 = 非关系数据库 + 关系功能
并且,【关系功能】会占用掉90%的硬件资源以及90%的计算时间。
很多互联网公司,有大量业务,不需要关系功能,非关系数据库就能搞定。因此,非关系型数据库就火起来了。
不过我们也不必纠结于此,毕竟现在还不是需要我们掌握它们的区别的时候,大概有个概念就可以
接下来我们主要看看Redis,毕竟主角是它。
Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
重点标红
相关的Redis在Windows下的安装我再昨天的日报中已经写过了,但是昨天的范例只是用了String存值,今天带来另外几种,这就是它比Memcache强大的地方!
首先我们看看hash存值
常用相关命令如下
序号 | 命令及描述 |
---|---|
1 | HDEL key field2 [field2] 删除一个或多个哈希表字段 |
2 | HEXISTS key field 查看哈希表 key 中,指定的字段是否存在。 |
3 | HGET key field 获取存储在哈希表中指定字段的值。 |
4 | HGETALL key 获取在哈希表中指定 key 的所有字段和值 |
7 | HKEYS key 获取所有哈希表中的字段 |
8 | HLEN key 获取哈希表中字段的数量 |
9 | HMGET key field1 [field2] 获取所有给定字段的值 |
10 | HMSET key field1 value1 [field2 value2 ] 同时将多个 field-value (域-值)对设置到哈希表 key 中。 |
11 | HSET key field value 将哈希表 key 中的字段 field 的值设为 value 。 |
12 | HSETNX key field value 只有在字段 field 不存在时,设置哈希表字段的值。 |
13 | HVALS key 获取哈希表中所有值 |
可以看到,获取hash表中指定key的全部value值
看一下这个HGET的命令,其中第三个值,并不是我开始认为的hash表中的位置值,而是设置hash表时候的相应的key-value值,可能这么说有点乱
我的存值命令是这样的
HMSET runoobkey name "redis tutorial" description "redis basic commands for caching" likes 20 visitors 23000
可以看到其中存在四个key-value对,分别是:name :“redis tutorial”和description :“redis basic commands for caching”以及likes :20,visitors :23000。
所以如我上图所示,HGET这个命令的使用需要注意一下
你可能会想,这我也不好看有什么键值对啊,别急,有命令可以让你一目了然
HLEN查的是hash表中字段的数量,也就是说,你有几个键值对
这里有两个新命令,HVALS key,输出hash表中所有值(就是key-value中的value),看效果,其实和HKEYS搭配起来效果最佳!
最后是HSET key field value命令,可以更改对应的field的值(就是hash表中key-value中的key,改变的是value),如上我将likes属性的20改为200.
以上就是Redis对于hash表的操作。
接下来继续骚,开始对List的操作
先贴一点简单命令
1 | BLPOP key1 [key2 ] timeout 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 |
2 | BRPOP key1 [key2 ] timeout 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 |
4 | LINDEX key index 通过索引获取列表中的元素 |
5 | LINSERT key BEFORE|AFTER pivot value 在列表的元素前或者后插入元素 |
6 | LLEN key 获取列表长度 |
7 | LPOP key 移出并获取列表的第一个元素 |
8 | LPUSH key value1 [value2] 将一个或多个值插入到列表头部 |
9 | LPUSHX key value 将一个值插入到已存在的列表头部 |
10 | LRANGE key start stop 获取列表指定范围内的元素 |
11 | LREM key count value 移除列表元素 |
12 | LSET key index value 通过索引设置列表元素的值 |
13 | LTRIM key start stop 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。 |
14 | RPOP key 移除并获取列表最后一个元素 |
命令太多了,我就测几个玩一玩
这两个箭头是报错的地方,第一个因为和之前hash表名字重复;第二个因为没有设置timeout时间参数
其他应该都看的懂
这个是排队阻塞的效果
可以看到对列表,是对列表头进行操作,就是你第一个插入的数据并不是处于第一位,而是最后一位,像入栈,只不过栈指针和这个不太一样。
可以看到移除命令报错,因为少参数,这里为了确保移除操作的安全性,命令中必须有你需要移除的值,否则拒绝移除命令。
列表的操作到此告一段落
看一下对Set集合的操作
老规矩
1 | SADD key member1 [member2] 向集合添加一个或多个成员 |
2 | SCARD key 获取集合的成员数 |
3 | SDIFF key1 [key2] 返回给定所有集合的差集 |
5 | SINTER key1 [key2] 返回给定所有集合的交集 |
7 | SISMEMBER key member 判断 member 元素是否是集合 key 的成员 |
8 | SMEMBERS key 返回集合中的所有成员 |
9 | SMOVE source destination member 将 member 元素从 source 集合移动到 destination 集合 |
10 | SPOP key 移除并返回集合中的一个随机元素 |
11 | SRANDMEMBER key [count] 返回集合中一个或多个随机数 |
12 | SREM key member1 [member2] 移除集合中一个或多个成员 |
13 | SUNION key1 [key2] 返回所有给定集合的并集 |
然后我就随便贴一下,大概看一下就行了
首先重名不行,添加重复元素没有用,这里有个点挺有意思的,就是最开始插入的两个元素的顺序是反的,以后插入的就是正常的了,不清楚为什么。
这里注意去差集的时候是有顺序问题的
SPOP是随机删除,挺危险的操作
SREM的操作和前面的一样,必须指定value的值,否则删除失败。
Set集合介绍到此结束。
就在我们在进行上述操作的时候,其实Redis已经对我们这些操作进行了处理,它会将我们之前存储的数据写入磁盘,看一下主界面里的内容
我们去相关文件路径下会发现一个数据库的文件,里面的内容就是我们之前操作的数据
接下来看一下发布订阅功能
下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:
当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:
通过SUBSCRIBE命令订阅频道,使用PUBLISH命令发送命令
看下图实例
就是需要开一堆cmd,挺烦的。
然后我们可以测试Redis的连接,通过PING命令,如果通了,会返回PONG
还有使用INFO可以查询一系列信息
最后以Redis事务做结尾
Redis 事务可以一次执行多个命令, 并且带有以下两个重要的保证:
- 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
- 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
一个事务从开始到执行会经历以下三个阶段:
- 开始事务。
- 命令入队。
- 执行事务。
如下实例
这里面巧妙的使用了“21天精通C++”(哈哈哈哈哈哈哈哈)
至此,我关于Redis的简单介绍就这么介绍完了。接下来就要开始关注Redis的jar包了。
首先,我们需要引入相关jar包
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
然后我们写两个测试方法,看看能不能使用Redis
import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/**
* Created by yubotao on 2017/09/01.
*/
public class TestRedis {
/**
* Redis存储字符串
*/
@Test
public void testString(){
Jedis jedis = new Jedis("127.0.0.1",6379);
jedis.set("name","xinxin");
System.out.println(jedis.get("name"));
//拼接
jedis.append("name"," is a sillyB");
System.out.println(jedis.get("name"));
//删除键
jedis.del("name");
System.out.println(jedis.get("name"));
//设置多个键值对
jedis.mset("name","liuling","age","23","qq","476777XXX");
// 对键值进行加1操作
jedis.incr("age");
System.out.println(jedis.get("name") + "-" + jedis.get("age") + "-" + jedis.get("qq"));
jedis.del("name");
jedis.del("age");
jedis.del("qq");
System.out.println(jedis.get("name") + "-" + jedis.get("age") + "-" + jedis.get("qq"));
System.out.println(jedis);
//这三个方法只有quit是直接断开服务器连接的,其他的貌似都不好使,quit后再调用jedis对象会报错。其他的两个再次调用都没什么问题
//
jedis.close();
jedis.quit();
jedis.disconnect();
//挺难受的,由于close方法是最近一年左右新更的,所以相关资料特别少,目前不知道怎么回事。搁置
jedis.set("name","No?");
System.out.println(jedis.get("name"));
System.out.println(jedis);
}
@Test
public void testRedisPool(){
Jedis jedis = RedisUtil.getJedis();
jedis.set("newname","中文测试");
System.out.println(jedis.get("newname"));
jedis.close();
System.out.println(jedis.get("newname"));}
}
然后看一下第二个测试类使用的RedisUtil的代码是啥
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/**
* Created by yubotao on 2017/09/01.
*/
public final class RedisUtil {
//Redis服务器IP
private static String ADDR = "127.0.0.1";
//Redis端口号
private static int PORT = 6379;
//可用连接实例的最大数目,默认值为8;
//如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
//没用上,尴尬,config没这个set方法
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.setMaxIdle(MAX_IDLE);
config.setMaxWaitMillis(MAX_WAIT);
config.setTestOnBorrow(TEST_ON_BORROW);
jedisPool = new JedisPool(config,ADDR,PORT,TIMEOUT);
}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 close(final Jedis jedis){
if(jedis != null){
jedis.close();
}
}
}
这里最后的jedis.close()存疑,由于资料很少,所以暂时就搁置。
然后运行程序,你可能会遇到错误,因为记得要在本地把Redis的服务启动。
开着这个界面跑程序吧
就不放测试结果了。暂时就这样吧。
明天计划:将Redis加入到项目中,并进行JMeter测试,形成压测报告,完成任务6.
问题:无
收获:Redis的使用。
评论