今日内容

  • nosql系列产品之 redis(非关系型数据库)
  • redis数据结构【重点】
  • redis相关命令
  • redis持久化机制【面试题】
  • jedis【相当于jdbc,远程操作redis数据库】


第一章 NoSQL

1.NoSQL介绍

NoSQL,泛指非关系型的数据库,NoSQL即Not-Only SQL,它可以作为关系型数据库的良好补充。

为什么学习NoSQL?

互联网产品的特点:高并发、高可用、高性能、海量数据

关系型数据库与NoSQL数据库并非对立而是互补的关系,即通常情况下使用关系型数据库,在适合
使用NoSQL的时候使用NoSQL数据库,NoSQL数据库对关系型数据库的不足进行弥补。

2. NoSQL的主流产品

分类

特点

代表产品

键值存储

数据一般存在内存中,读写速度快(10w/s),适合作为缓存服务

redis

文档型数据库

数据结构要求不严格,适合存储结构不确定或者价值较低的数据

mongdb

列存储数据库

查找速度快,更容易进行分布式扩展,适合作为文件存储服务

Hbase

图形数据库

使用“图结构”进行存储,适合做社交网络计算等等

Neo4j

图形数据库介绍

关系数据库,只需要学习一套SQL规范,就可以操作几乎所有关系数据库

非关系型数据库,每一种产品都是独立的,比如进行学会了redis、mongodb

第二章 Redis

1. Redis介绍

Redis(Remote Dictionary Server)是用C语言开发的一个开源的高性能键值对数据库。它的所有数据都是保存在内存中的,这也就决定了其读写速度之快,是其它硬盘保存数据的系统所无法匹敌的。

官方曾经给出过一组测试数据,50个并发执行100000个请求: 读的速度是110000次/s,写的速度是81000次/s

2. Redis服务器安装和使用

下载

安装

windows绿色版,解压即用

目录

文件

作用

redis.windows.conf

核心配置文件

redis-benchmark.exe

redis-check-aof.exe

redis-check-dump.exe

redis-cli.exe

redis命令行客户端

redis-server.exe

启动redis数据库服务

目录或文件

作用

redis-benchmark

性能测试工具

redis-check-aof

AOF文件修复工具

redis-check-dump

RDB文件检查工具(快照持久化文件)

redis-cli

命令行客户端

redis-server

启动redis服务器

redis.windows.conf

redis核心配置文件

启动

windows平台使用

[16552] 15 Sep 17:52:39.930 # Warning: no config file specified, using the default config. In order to specify a config file use D:\develop\Redis-x64-3.0.503\redis-server.exe /path/to/redis.conf
                _._
           _.-``__ ''-._
      _.-``    `.  `_.  ''-._           Redis 3.0.503 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 16552
  `-._    `-._  `-./  _.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |           http://redis.io
  `-._    `-._`-.__.-'_.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |
  `-._    `-._`-.__.-'_.-'    _.-'
      `-._    `-.__.-'    _.-'
          `-._        _.-'
              `-.__.-'

[16552] 15 Sep 17:52:39.935 # Server started, Redis version 3.0.503
[16552] 15 Sep 17:52:39.935 * DB loaded from disk: 0.000 seconds
[16552] 15 Sep 17:52:39.935 * The server is now ready to accept connections on port 6379

linux平台使用

* 在当前解压后的目录下  cmd进入dos窗口
		先启动 redis-server.exe redis.windows.conf
		再启动 redis-cli.exe

3. Redis数据结构【重点】

Redis采用的是键值对存储,键的类型只能为字符串,值支持五种数据类型:

  • 字符串:String
  • 哈希:HashMap
  • 双向链表:LinkedList
  • 无序集合:HashSet
  • 有序集合:LinkedHashSet

4. Redis命令操作

Redis命令是用来操作Redis数据库的, 就相当于操作MySql数据库时的SQL语句。

Redis的命令根据要操作的值的数据结构的不同而不同, 每种数据类型都有自己的操作命令

4.1 String 字符串【重点】

字符串类型是Redis中最为基础的数据存储类型。

在Redis中字符串类型的Value最多可以容纳的数据长度是512m。

* 新增(更新)
		set key "value" 
		注意:value值内容有空格,外面需要加引号
* 查询
		get key
* 删除
		del key
* 新增并指定存活时间
		setex key seconds value
		ttl key  查看存活时间

* 根据键判断记录是否存在
		exists key
		
* 主键自增(类似于MySQL中的,auto_increment)
		set id 1
		incr id

新增(修改)

127.0.0.1:6379> set mystr  mryhl
OK

查询

127.0.0.1:6379> get mystr
"mryhl"

删除

127.0.0.1:6379> del mystr1
(integer) 1

新增并指定存活时间

127.0.0.1:6379> setex sms_code 10  234534
OK

查看存活时间

127.0.0.1:6379> ttl sms_code
(integer) 1
127.0.0.1:6379> ttl sms_code
(integer) -2

根据键判断记录是否存在

127.0.0.1:6379> exists sms_code
(integer) 0
127.0.0.1:6379> setex sms_code 10  234534
OK
127.0.0.1:6379> exists sms_code
(integer) 1

自增主键

127.0.0.1:6379> set id 1
OK
127.0.0.1:6379> incr id
(integer) 2
127.0.0.1:6379> incr id
(integer) 3

4.2 Hash 哈希

Hash类型极其类似于java中的Map,值里面可以存放一组组的键值对

该类型非常适合于存储java中对象的信息

* 新增(更新)
		hset key hkey hvalue
* 查询
		hget key hkey 查询具体元素
		hgetall key   查询所有元素
* 删除
		hdel key hkey 删除指定元素
		del  key      删除整个hash

新增、更新

127.0.0.1:6379> hset user_1 id 1
(integer) 1
127.0.0.1:6379> hset user_1 name tom
(integer) 1
127.0.0.1:6379> hset user_1 age 18
(integer) 1

查询

127.0.0.1:6379> hget user_1 name
"tom"

查询所有

127.0.0.1:6379> hgetall user_1
1) "id"
2) "1"
3) "name"
4) "tom"
5) "age"
6) "18"

删除

127.0.0.1:6379> hdel user_1 age
(integer) 1
127.0.0.1:6379> hgetall user_1
1) "id"
2) "1"
3) "name"
4) "tom"

4.3 List 列表

List类型底层是一个双向字符串链表。里面的元素是有序的,可重复的

我们可以从链表的任何一端进行元素的增删

新增:
	lpush key value 从左侧顶端添加元素
	rpush key value 从右侧顶端添加元素
查询:
	lrange key start end
	0-1(查询所有)
删除:
	1pop key 从左侧弹出一个元素
	rpop key 从右侧弹出一个元素
127.0.0.1:6379> lpush mylist a
(integer) 1
127.0.0.1:6379> lpush mylist b
(integer) 2
127.0.0.1:6379> lpush mylist c
(integer) 3
127.0.0.1:6379> rpush mylist d
(integer) 4

查询

127.0.0.1:6379> lrange mylist 0 -1
1) "c"
2) "b"
3) "a"
4) "d"

删除

127.0.0.1:6379> lpop mylist
"c"
127.0.0.1:6379> rpop mylist
"d"

补充:如果插入顺序和查询顺序一致,请使用rpush添加元素

4.4 Set 集合(无序)

Set类型底层是一张hash表。里面的元素是无序的,不可重复的

* 新增
		sadd key value
* 查询
		smembers key
* 删除
		srem key value

新增

127.0.0.1:6379> sadd myset timo
(integer) 1
127.0.0.1:6379> sadd myset jack
(integer) 1
127.0.0.1:6379> sadd myset lucy
(integer) 1

查询

127.0.0.1:6379> smembers myset
1) "jack"
2) "lucy"
3) "timo"

删除

127.0.0.1:6379> srem myset anni
(integer) 0
127.0.0.1:6379> srem myset jack
(integer) 1
127.0.0.1:6379> smembers myset
1) "lucy"
2) "timo"

4.5 ZSet 集合(有序)

Zset,也称sortedSet, 在Set的基础上,加入了有序功能,在添加元素的时候,允许指定一个分数,它会按照这个分数排序

* 新增
		zadd key 分值 value
* 查询
		zrange key start end [withscores] 升序
		zrevrange key start end [withscores] 降序
* 删除
		zrem key value

新增

127.0.0.1:6379> zadd myzset 56 tom
(integer) 1
127.0.0.1:6379> zadd myzset 20 haley
(integer) 1
127.0.0.1:6379> zadd myzset 2 jek
(integer) 1

查询

127.0.0.1:6379> zrange myzset 0 -1
1) "jek"
2) "haley"
3) "tom"
127.0.0.1:6379> zrange myzset 0 -1 withscores
1) "jek"
2) "2"
3) "haley"
4) "20"
5) "tom"
6) "56"

倒序

127.0.0.1:6379> zrevrange myzset 0 -1 withscores
1) "tom"
2) "56"
3) "haley"
4) "20"
5) "jek"
6) "2"

删除

127.0.0.1:6379> zrem myzset jek
(integer) 1
127.0.0.1:6379> zrevrange myzset 0 -1 withscores
1) "tom"
2) "56"
3) "haley"
4) "20"

4.6 通用命令

* 模糊查询键
		keys *
		
* 删除多个键
		del key [key] [key]

* 根据键判断值类型 
		type key

* 选择数据库
		select 库名[0~15]
		
* 清空当前数据库
		flushdb

* 清空所有数据库
		flushall

5.Redis持久化【面试题】

Redis的数据都是存在在内存之中的,那么这样一旦出现宕机,势必会导致数据的丢失,这就需要持久化操作,也就是要将redis在内存中的数据写到硬盘上保存。

注意:redis虽然有持久化操作,但是其全部数据依旧都在内存中存在,也就是说硬盘上的只是为了安全和备份。

Redis提供了两种数据持久化的方式,分别是RDB和AOF。

RDB:默认开启,不需要配置

* 手动持久化【了解】
		bgsave
		
* 自动持久化
	在redis运行期间,根据指定时间规则,将内存的数据集进行快照拍摄,持久化到硬盘 【dump.rdb】
	在redis.windows.conf配置文件中,可以查看(修改)时间规则
        save 900 1
        save 300 10
        save 60 10000
################################ SNAPSHOTTING  ################################
#
# Save the DB on disk:
#
#   save <seconds> <changes>
#
#   Will save the DB if both the given number of seconds and the given
#   number of write operations against the DB occurred.
#
#   In the example below the behaviour will be to save:
#   after 900 sec (15 min) if at least 1 key changed
#   after 300 sec (5 min) if at least 10 keys changed
#   after 60 sec if at least 10000 keys changed
#
#   Note: you can disable saving completely by commenting out all "save" lines.
#
#   It is also possible to remove all the previously configured save
#   points by adding a save directive with a single empty string argument
#   like in the following example:
#
#   save ""

save 900 1
save 300 10
save 60 10000

AOF:默认关闭,需手动开启

* 在redis运行期间,以日志记录方式监控写操作,持久化到硬盘【appendonly.aof】

* 在redis.windows.conf配置文件中开启
		appendonly no --> appendonly yes
		
* 三种日志监控规则
	# appendfsync always 每次(写操作)修改时,进行持久化
    appendfsync everysec 每秒,持久化一次
    # appendfsync no     在CPU空闲期,进行持久化

RDB和AOF二种持久化机制可以同时存在

在开发中使用哪种机制进行持久化?

* RDB:应用在缓存服务器场景
	优点:性能高,降低磁盘IO
	缺点:redis容灾后,容易丢失数据
	
* AOF:应用在数据库服务器场景
	优点:不容易丢失数据(日志)
	缺点:速度稍慢(能够秒杀mysql等产品的...)

6 应用场景

  • 缓存【重点】
  • 秒杀
  • 微博热搜
  • 分布式session
  • 数据过期处理

第三章 Jedis【重点】

Redis作为一款优秀的缓存服务器存在,大多数语言都提供了连接Redis的驱动包,在java中,比较出名的是Jedis和Redisson,我们今天以Jedis为例学习,看看如何是用程序操作redis。

1 Jedis使用

常用API

方法

解释

new Jedis(host, port)

创建jedis对象,参数host是redis服务器地址,参数port是redis服务端口

set(key,value)

设置字符串类型的数据

get(key)

获得字符串类型的数据

hset(key,field,value)

设置哈希类型的数据

hget(key,field)

获得哈希类型的数据

lpush(key,values)

设置列表类型的数据

lpop(key)

列表左面弹栈

rpop(key)

列表右面弹栈

del(key)

删除指定的key

快速入门

① 导入相关坐标【已完成】

<!--jedis-->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.0</version>
        </dependency>

maven官方提供坐标搜索仓库:https://mvnrepository.com/

② 编写代码

public class JedisTest {

    @Test
    public void test01()throws Exception{
        // 1.创建jedis连接对象
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        // 2.调用set方法
        jedis.set("mystr", "传智播客");
        // 3.释放资源
        jedis.close();
    }

    @Test
    public void test02()throws Exception{
        // 1.创建jedis连接对象
        Jedis jedis = new Jedis();
        // 2.调用get方法
        System.out.println(jedis.get("mystr"));
        // 3.释放资源
        jedis.close();
    }
}

2. Jedis连接池

jedis连接资源的创建与销毁是非常消耗性能的,所以我们不希望频繁的创建和销毁它.基于这样的需求,就有了jedisPool技术。

快速入门

public class JedisPoolTest {

    @Test
    public void test01() throws Exception {
        // 1.创建连接池对象
        JedisPool jedisPool = new JedisPool("127.0.0.1", 6379);
        // 2.从池中获取连接
        Jedis jedis = jedisPool.getResource();
        // 3.操作api实现CRUD
        jedis.setex("sms_code", 300, "996571");
        // 4.归还到连接池
        jedis.close(); // 底层使用了动态代理,进行增强
    }

    @Test
    public void test02() throws Exception {
        // 指定连接池配置参数
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(50); // 最大连接数
        config.setMinIdle(10); // 空闲期,保留连接数
        config.setMaxWaitMillis(3000);// 等待时间

        // 1.创建连接池对象
        JedisPool jedisPool = new JedisPool(config, "127.0.0.1", 6379);
        // 2.从池中获取连接
        Jedis jedis = jedisPool.getResource();
        // 3.操作api实现CRUD
        System.out.println(jedis.get("sms_code"));

        // 4.归还到连接池
        jedis.close(); // 底层使用了动态代理,进行增强
    }
}

连接池工具栏

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.ResourceBundle;

/*
 *   jedis工具类
 * */
public class JedisUtils {

    private static JedisPool jedisPool;

    private static String host;
    private static Integer port;
    private static Integer maxTotal;
    private static Integer maxIdle;

    // 初始化连接池
    static {
        try {

            ResourceBundle jedis = ResourceBundle.getBundle("jedis");


            // 读取配置文件给变量赋值
            // 获取类加载读取 jedis.properties 获取io流
            InputStream is = JedisUtils.class.getClassLoader().getResourceAsStream("jedis.properties");
            // 创建properties对象 加载io流
            Properties properties = new Properties();
            properties.load(is);
            // 给变量赋值
            host = properties.getProperty("jedis.host");
            port = Integer.parseInt(properties.getProperty("jedis.port"));
            maxTotal = Integer.parseInt(properties.getProperty("jedis.maxTotal"));
            maxIdle = Integer.parseInt(properties.getProperty("jedis.maxIdle"));

            // 创建连接池配置对象
            JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
            jedisPoolConfig.setMaxTotal(maxTotal);
            jedisPoolConfig.setMaxIdle(maxIdle);
            // 创建连接池对象
            jedisPool = new JedisPool(jedisPoolConfig, host, port);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 提供获取jedis连接的方法
    public static Jedis getJedis() {
        return jedisPool.getResource();
    }
}

3. 注意事项

在启动项目时,或访问需求是,控制台报错了,连接reids超时,基本只有一个原因,redis没启动成功