J自我学习+整理--Redis

Redis:NoSQL数据库

NoSQL:

目前市场主流数据存储都是使用关系型数据库。每次操作关系型数据库时都是I/O操作,I/O操作是主要影响程序执行性能原因之一,连接数据库关闭数据库都是消耗性能的过程。关系型数据库索引数据结构都是树状结构,当数据量特别大时,导致树深度比较深,当深度深时查询性能会大大降低。尽量减少对数据库的操作,能够明显的提升程序运行效率。
针对上面的问题,市场上就出现了各种NoSQL(Not Only SQL,不仅仅可以使用关系型数据库)数据库,它们的宣传口号:不是什么样的场景都必须使用关系型数据库,一些特定的场景使用NoSQL数据库更好。
常见NoSQL数据库:
memcached :键值对,内存型数据库,所有数据都在内存中。
Redis:和Memcached类似,还具备持久化能力。
HBase:以列作为存储。
MongoDB:以Document做存储。

Redis:

存储方式是键值对:key: value
Redis的底层是C语言编写的
Redis是把数据存储到内存里;
Redis以slot(槽)作为数据存储单元,每个槽中可以存储N多个键值对。Redis中固定具有16384。理论上可以实现一个槽是一个Redis。每个向Redis存储数据的key都会进行crc16算法得出一个值后对16384取余就是这个key存放的slot位置。

Redis常用命令:

Redis的常用数据类型:
1.String 字符串
2.Hash 哈希表
3.List 列表
4.Set 集合
5.Zset 有序集合

通用操作:
1.Exists 判断key是不是存在,语法:exists key名称, 返回值:成功返回1,失败返回0
在这里插入图片描述在这里插入图片描述

2.Expire 设置key的过期时间,单位是秒,语法:expire key 秒数, 返回值:成功返回1,失败返回0
在这里插入图片描述

3.Ttl 查看key的过期时间, 语法ttl key,语法:返回值:剩余时间,如果不过期-1,如果数据不存在-2,过期时间单位是秒

在这里插入图片描述
在这里插入图片描述

4.Persist 删除已有的有效期,语法: persist key
在这里插入图片描述

5.Del 根据key删除键值对,可以批量删除,不推荐使用。集群环境下redis不支持批量删除。语法:del key […],返回值:被删除的key的数量
在这里插入图片描述

6.Keys* 命令:keys* 查看所有存在的key
在这里插入图片描述

7.Flushall 清空redis中所有的键值对,语法flushall
8.Dbsize 返回redis中数据库中的键值对数量
在这里插入图片描述

9.Select 切换使用的数据库,Redis默认有16个数据库,编号是0~15。默认连接redis使用的是0号数据库,可以自由切换数据库,select 数据库
在这里插入图片描述

字符串值(String)
1.Set:设置指定的key的值,如果key不存在是新增效果,如果key存在是修改效果,键值对是永远存在的;
在这里插入图片描述

2.Get:获取key的值
在这里插入图片描述

3.Setnx:当且仅当key不存在时才新增,如果key存在,将不修改值;
在这里插入图片描述

底层:

setnx具备分布式锁能力。在编写代码时如果调用setnx,时会对代码进行加锁。直到删除该key时会解锁。
setnx();// 加锁
// 代码
del();//解锁。
如果在并发访问时第一个线程setnx()时发现没有指定key会正常向下运行。其他线程在执行setnx()时发现有这个key就会等待,等待第一个线程删除key时才会继续向下执行。
常见的锁
锁:在Java中可以通过锁,让多线程执行时某个代码块或方法甚至类是线程安全的。通俗点说:一个线程访问,别的线程需要等待。
线程锁:同一个应用。多线程访问时添加的锁。synchronized(自动释放)或Lock(手动释放)
进程锁:不同进程(一个进程就是一个应用)需要访问同一个资源时,可以通过添加进程锁进行实现。
分布式锁:在分布式项目中不同项目访问同一个资源时,可以通过添加分布式锁保证线程安全。常见的分布式锁有两种:Redis的分布式锁和Zookeeper的分布式锁(通过调用Zookeeper的API给Zookeeper集群添加一个节点。如果节点能添加继续向下执行,执行结束删除该节点。如果其他线程发现该节点已经添加,会阻塞等待该节点删除才继续向下执行。)。
4.Setex:设置key的存活时间,无论是否存在指定key都能新增,如果存在key覆盖旧值。同时必须指定过期时间。语法:setex key time value
在这里插入图片描述

5.Mset:批量设置,一次性设置多个键值对;语法:mset key1 value1 key2 value2 …
在这里插入图片描述

6.Mget:批量查询,一次性查询多个key的value;语法:mget key1 key2 …

在这里插入图片描述

Hash表
给key中的field设置值;

Hset:语法:hset key field value…
返回值:成功 field数量 失败 0
在这里插入图片描述

Hget:获取hash表的key的field的值
在这里插入图片描述

Hmset:给key中多个value赋值
在这里插入图片描述

Hmget:一次获取多个key的field值
在这里插入图片描述

Hvals:获取key中所有field的值
在这里插入图片描述

Hgetall:获取所有field和value
在这里插入图片描述

Hdel:删除一个key的field
在这里插入图片描述

Hkeys:获取hash中所有的field
在这里插入图片描述

List 列表
Rpush:向列表末尾插入一个或多个值
在这里插入图片描述

Lrange:返回列表中指定区间的值。可以用-1代表末尾,list下标有两种计数方式,
头->尾:0,1,2,3… 尾->头:-1,-2,-3…
在这里插入图片描述

Lpush:将一个或多个值插入列表的前面
在这里插入图片描述

Llen:获取列表长度
在这里插入图片描述

Lrem:删除列表中的元素。Count为整数从左向右删除的数量,负数从右向左删除;

在这里插入图片描述

Set集合
set和java中集合一样。不允许重复值,如果插入重复值,后新增返回结果为0。
Sadd:向集合内添加元素,不允许重复
在这里插入图片描述

Scard:返回集合元素数量
在这里插入图片描述

Smemebers:查看集合中的元素
在这里插入图片描述

Srem:删除集合中的元素
在这里插入图片描述

SortSet 有序集合
有序集合中每个value都有一个分数(score),根据分数进行排序。同分数的,按照value的asc码升序排列。
Zadd:向有序集合中添加数据
在这里插入图片描述

Zrange:返回区间内容,withscore 带分数
在这里插入图片描述

Zcard:返回集合中元素的数量
在这里插入图片描述

Zrem:删除集合中元素

在这里插入图片描述

Redis的持久化策略:

Redis不仅仅是一个内存型数据库,还具备持久化能力。
Redis每次启动时都会从硬盘存储文件中把数据读取到内存中。运行过程中操作的数据都是内存中的数据。
一共包含两种持久化策略:RDB 和 AOF

RDB(Redis DataBase)

rdb模式是默认模式,可以在指定的时间间隔内生成数据快照(snapshot),默认保存到dump.rdb文件中。当redis重启后会自动加载dump.rdb文件中内容到内存中。
用户可以使用SAVE(同步)或BGSAVE(异步)手动保存数据。
可以设置服务器配置的save选项,让服务器每隔一段时间自动执行一次BGSAVE命令,可以通过save选项设置多个保存条件,但只要其中任意一个条件被满足,服务器就会执行BGSAVE命令。
  例如:
  save 900 1
  save 300 10
  save 60 10000
  那么只要满足以下三个条件中的任意一个,BGSAVE命令就会被执行。计时单位是必须要执行的时间,save 900 1 ,每900秒检测一次。在并发量越高的项目中Redis的时间参数设置的值要越小。
  服务器在900秒之内,对数据库进行了至少1次修改
  服务器在300秒之内,对数据库进行了至少10次修改
  服务器在60秒之内,对数据库进行了至少10000次修改。

优点
rdb文件是一个紧凑文件,直接使用rdb文件就可以还原数据。
数据保存会由一个子进程进行保存,不影响父进程做其他事情。
恢复数据的效率要高于aof
总结:性能要高于AOF
缺点
每次保存点之间导致redis不可意料的关闭,可能会丢失数据。
由于每次保存数据都需要fork()子进程,在数据量比较大时可能会比较耗费性能。

AOF(AppendOnly File)

AOF默认是关闭的,需要在配置文件redis.conf中开启AOF。Redis支持AOF和RDB同时生效,如果同时存在,AOF优先级高于RDB(Redis重新启动时会使用AOF进行数据恢复)
AOF原理:监听执行的命令,如果发现执行了修改数据的操作,同时直接同步到数据库文件中,同时会把命令记录到日志中。即使突然出现问题,由于日志文件中已经记录命令,下一次启动时也可以按照日志进行恢复数据,由于内存数据和硬盘数据实时同步,即使出现意外情况也需要担心。
优点
相对RDB数据更加安全。
缺点
相同数据集AOF要大于RDB。
相对RDB可能会慢一些。
开启办法
修改redis.conf中。
appendonly yes 开启aof
appendfilename 设置aof数据文件,名称随意。

Java通过spring-data-redis操作rediis

首先添加spring-boot-starter-data-redis的pom依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>new_redis_client</artifactId>
        <groupId>com.lzl</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>client_data_redis</artifactId>


    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.3.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>2.4.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.11.3</version>
        </dependency>
    </dependencies>
</project>

创建连接redis的配置文件:

spring:
  redis:
    host: 192.168.142.130
    port: 6379

创建RedisTemplate的配置类:

package com.lzl.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class MyDataRedisConfiguration {
    /**
     * springboot-starter-data-redis 会默认提供一个redisTemplate类型的对象,
     * 连接的地址通过配置文件设置,默认localhost:6379
     * 默认提供的RedisTemplate的类型是RedisTemplate<Object,Object>
     * key,value的类型可以是Object的兼容类型
     * 默认的redistemplate提供的序列化工具有固定的配置,
     * key是字符串序列化,value是jdk的Serializable提供的序列化工具
     * @return
     */
    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory connectionFactory){
        //redisConnectionFactory是spring-data-redis提供的连接工厂对象.Template只负责读写,不负责连接
        //连接工厂,由springboot-starter-data-redis自动创建,连接的配置由配置文件决定
        RedisTemplate<String , Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(connectionFactory);

        // 增加序列化工具,改变key和value的序列化方式
        // 设置key的序列化器,为字符串序列化器,只处理字符串,且不会通过Serializable实现。
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        // 设置value的序列化器,为JSON序列化器。序列化结果是: {"属性名": "属性值", "@class": "包名.类型"}
        // 必须依赖jackson
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());

        //设置hash数据的field和value的序列化器
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());


        return redisTemplate;
    }
}

创建启动类:

package com.lzl;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication
public class MdataRedisApp {
    public static void main(String[] args) {
        SpringApplication.run(MdataRedisApp.class,args);
    }
}

创建test测试类:

package com.lzl.test;

import com.lzl.MdataRedisApp;
import com.lzl.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.*;
import java.util.concurrent.TimeUnit;

@SpringBootTest(classes = {MdataRedisApp.class})
@RunWith(SpringRunner.class)
public class TestDataRedis {
    //由configuration创建
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Test
    public void testDel(){
        //单独删除
        redisTemplate.delete("myyUsers");
        //批量删除
        redisTemplate.delete(Arrays.asList("myUsers2","data-redis-2"));
    }


    @Test
    public void testList2String(){
        List<User> users = new ArrayList<>();
        users.add(new User("admin",20,"male"));
        users.add(new User("admin4",20,"male"));
        users.add(new User("admin5",20,"male"));
        users.add(new User("admin6",20,"male"));
        redisTemplate.opsForValue().set("myUsers2",users);

        List<User> myUsers2 = (List<User>) redisTemplate.opsForValue().get("myUsers2");
        System.out.println(myUsers2);
    }


    //不推荐使用
    @Test
    public void testList(){
        redisTemplate.opsForList().rightPushAll("myUsers",
                new User("admin",20,"male"),
                new User("admin1",20,"male"),
                new User("admin2",20,"male"),
                new User("admin3",20,"male")
        );

        List<Object> myUsers = redisTemplate.opsForList().range("myUsers", 0, -1);
        System.out.println(myUsers);
    }


    @Test
    public void testHash(){
        HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
        hash.put("stu2","name","lzl");
        Map<String,String> map = new HashMap<>();
        map.put("gender","man");
        map.put("age","20");
        hash.putAll("stu2",map);

        Map<Object, Object> stu = hash.entries("stu2");
        System.out.println(stu);
    }


    @Test
    public void testExpire(){
        redisTemplate.expire("data-redis-1",50, TimeUnit.SECONDS);
        Long expire = redisTemplate.getExpire("data-resis-1");
        System.out.println("剩余有效期:"+expire);
        //永久保存
        redisTemplate.persist("data-redis-1");
    }

    @Test
    public void testGet(){
        //因为RedisTemplate泛型是<String,Object>,所以查询结果类型一定是Object
        System.out.println(redisTemplate.opsForValue().get("data-redis-1"));
        System.out.println(redisTemplate.opsForValue().get("data-redis-2"));

        Object value = redisTemplate.opsForValue().get("data-redis-2");
        System.out.println(value.getClass().getName());
    }


    @Test
    public void testSet(){
        //opsForxxx获取某数据类型的读写访问操作对象
        //opsForValue对应的是字符串读写
        //opsForList() List列表读写
        ValueOperations<String, Object> operations = redisTemplate.opsForValue();
        operations.set("data-redis-1","测试spring-data-redis");
        operations.set("data-redis-2",new User("张三",20,"男"));
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

so_defficult

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值