发表于: 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存值

常用相关命令如下

序号命令及描述
1HDEL key field2 [field2] 
删除一个或多个哈希表字段
2HEXISTS key field 
查看哈希表 key 中,指定的字段是否存在。
3HGET key field 
获取存储在哈希表中指定字段的值。
4HGETALL key 
获取在哈希表中指定 key 的所有字段和值

7HKEYS key 
获取所有哈希表中的字段
8HLEN key 
获取哈希表中字段的数量

9HMGET key field1 [field2] 
获取所有给定字段的值
10HMSET key field1 value1 [field2 value2 ] 
同时将多个 field-value (域-值)对设置到哈希表 key 中。
11HSET key field value 
将哈希表 key 中的字段 field 的值设为 value 。
12HSETNX key field value 
只有在字段 field 不存在时,设置哈希表字段的值。
13HVALS 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的操作

先贴一点简单命令

1BLPOP key1 [key2 ] timeout 
移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
2BRPOP key1 [key2 ] timeout 
移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
4LINDEX key index 
通过索引获取列表中的元素
5LINSERT key BEFORE|AFTER pivot value 
在列表的元素前或者后插入元素
6LLEN key 
获取列表长度
7LPOP key 
移出并获取列表的第一个元素
8LPUSH key value1 [value2] 
将一个或多个值插入到列表头部
9LPUSHX key value 
将一个值插入到已存在的列表头部
10LRANGE key start stop 
获取列表指定范围内的元素
11LREM key count value 
移除列表元素
12LSET key index value 
通过索引设置列表元素的值
13LTRIM key start stop 
对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。
14RPOP key 
移除并获取列表最后一个元素

命令太多了,我就测几个玩一玩

这两个箭头是报错的地方,第一个因为和之前hash表名字重复;第二个因为没有设置timeout时间参数

其他应该都看的懂

这个是排队阻塞的效果


可以看到对列表,是对列表头进行操作,就是你第一个插入的数据并不是处于第一位,而是最后一位,像入栈,只不过栈指针和这个不太一样。


可以看到移除命令报错,因为少参数,这里为了确保移除操作的安全性,命令中必须有你需要移除的值,否则拒绝移除命令。


列表的操作到此告一段落


看一下对Set集合的操作

老规矩

1SADD key member1 [member2] 
向集合添加一个或多个成员
2SCARD key 
获取集合的成员数
3SDIFF key1 [key2] 
返回给定所有集合的差集
5SINTER key1 [key2] 
返回给定所有集合的交集
7SISMEMBER key member 
判断 member 元素是否是集合 key 的成员
8SMEMBERS key 
返回集合中的所有成员
9SMOVE source destination member 
将 member 元素从 source 集合移动到 destination 集合
10SPOP key 
移除并返回集合中的一个随机元素
11SRANDMEMBER key [count] 
返回集合中一个或多个随机数
12SREM key member1 [member2] 
移除集合中一个或多个成员
13SUNION key1 [key2] 
返回所有给定集合的并集


然后我就随便贴一下,大概看一下就行了

首先重名不行,添加重复元素没有用,这里有个点挺有意思的,就是最开始插入的两个元素的顺序是反的,以后插入的就是正常的了,不清楚为什么。

这里注意去差集的时候是有顺序问题的

SPOP是随机删除,挺危险的操作

SREM的操作和前面的一样,必须指定value的值,否则删除失败。


Set集合介绍到此结束。


就在我们在进行上述操作的时候,其实Redis已经对我们这些操作进行了处理,它会将我们之前存储的数据写入磁盘,看一下主界面里的内容


我们去相关文件路径下会发现一个数据库的文件,里面的内容就是我们之前操作的数据


接下来看一下发布订阅功能

下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:

pubsub1

当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:

pubsub2


通过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的使用。



返回列表 返回列表
评论

    分享到