redis

目录

redis介绍

linux上redis安装

redis运行 

运行redis(前台启动)

 后台启动

​ 开机自启动

redis客户端 

命令行客户端

 图形化客户端

 Redis数据结构介绍

 一些通用命令

 string类型

 hash类型

 list类型

 set类型

 sortedSet类型​

redis的java客户端

Jedis连接池

SpringDataRedis

序列化问题

解决办法


redis介绍

redis是一个键值形式的数据库,其内部的数据以key-value的形式存储

 其value可以包含多种形式,比如list,hashmap等

redis是非关系型数据库,mysql是关系型数据库,区别在于

1、mysql里数据的存储是表,每一个字段可以添加约束,比如unique、not null等。而非关系型数据库没有这种严格的约束

2、mysql的表可以存在主外键约束,实现两个表的关联。非关系型数据库没有实现这种主外键约束。比如记录一个用户购买了什么东西,就要在购买表中记录购买商品的信息

 可以在item中只记录id,然后通过另外一个表,记录商品信息,但是这种表的关联需要程序员在业务逻辑中实现,redis是不存在主外键约束的。

3、mysql等关系型数据库的SQL语句是统一的,而非关系型数据库是每一种有不同的查询语言

4、mysql的事务满足ACID四种特性(原子性,隔离性,一致性,持久性),而非关系型数据库

要么没有事务,要么只能满足部分特性

5、关系型数据库数据一般存在于磁盘上,而非关系型数据库数据存在于内存中

6、在对性能要求高时,使用非关系型数据库

 

linux上redis安装

1、redis使用c语言编写,先安装所需依赖

 yum install -y gcc tcl

2、上传安装包并解压

tar -zxvf redis-7.0.11.tar.gz

3、进入redis目录

 cd redis-7.0.11

4、运行编译命令

 make && make install

5、检查是否安装成功(进入默认安装路径)

redis运行 

运行redis(前台启动)

redis-server

 后台启动

如果想让redis支持后台启动,就要修改配置文件

进入redis的安装目录

 找到redis-conf文件

 

 以配置文件的方式运行

进入安装路径  cd redis-7.0.11

启动运行 redis-server redis.conf

查看是否启动

 开机自启动

 1、建立系统服务文件

vi /etc/systemd/system/redis.service

2、文件内容

[Unit]
Description=redis-server
After=network.target
[Service]
Type=forking


ExecStart=/usr/local/bin/redis-server  /usr/local/src/redis-7.0.11/redis.conf
PrivateTmp=true
[Install]
WantedBy=multi-user.target

其中 ExecStart 前部分是redis的安装路径下的redis-server文件 后一部分是redis.conf的目录

3、重新加载服务

systemctl daemon-reload

4、以下命令可以执行操作

systemctl start redis  启动redis(启动之前杀死已经启动的redis进行)

systemctl status redis 查看redis启动

systemctl stop redis 停止redis

systemctl enable redis redis开机自启

redis客户端 

命令行客户端

1、命令行客户端 在安装redis时就已经被安装了

 2、操作

 

 可以使用-a输入密码 也可以使用 AUTH命令指定用户名和密码

 图形化客户端

下载RedisDesktopManager 软件

https://github.com/lework/RedisDesktopManager-Windows/releases

连接时要设置linux防火墙,让6379端口可通过,或者去服务器后台添加6379端口

systemctl start firewalld.service  开启防火墙服务

firewall-cmd --add-port=6379/tcp --permanent  开启6379端口

firewall-cmd --reload 刷新

firewall-cmd --permanent --query-port=80/tcp ##查看80端口有没开放

 比如在客户端操作

在命令行可以进行值的添加和读取

select index  [选择第index库,index从0-15]

set 字段  值

get 字段  [获取值]

 这里出现了中文乱码

Redis读取中文乱码问题的原因

Redis是一个基于内存的数据存储系统,其内部采用的是二进制数据存储方式。当向Redis中存储中文时,由于Redis只能识别二进制数据,所以需要将中文数据进行编码转换后才能正确存储。然而在读取数据时,如果没有进行正确的解码转换,就会出现中文乱码的情况。

在进入命令窗口时,加入--raw

 Redis数据结构介绍

redis是一个key-value形式的数据库,key一般就是字符串类型,而value有8种类型

 一些通用命令

1、keys:查询key

 2、del +key:删除某一个key

3、EXISTS+key:判断某一个key是否存在

4、EXPIRE key seconds [NX | XX | GT | LT] :给key设置有效期,过期后删除

5、TTL key:查看key的有效期

 string类型

 

 当有多个表设计到了id这个字段,redis没有表,如何区分多个id,否则设置另外一个id就会替换之前的id值

在id字段设置层级:比如 user:id;product:id

 

 key就实现了分级存储

 hash类型

 

 

 list类型

底层可以看作一个双向链表

  • LLEN:返回list的长度

 set类型

 sortedSet类型

 

 

 1、加入:ZADD stu 85 jack 89 LUCY 82 ROSE 95 TOM 78 JERRY 82 AMY 86 MILES

 2、删除tom:ZREM stu TOM

3、获取lucy的分数  ZSCORE stu LUCY

4、获取rose的排名 ZRANK stu rose

 5、85分以下的人数: ZCOUNT stu 0 85 

6、前三名的同学:

redis的java客户端

 

 1、创建一个maven工程,引入redis依赖

<!-- Redis 依赖 -->

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.1.0</version>
</dependency>

2、建立连接,调用API操作,关闭资源

public class Redis {
    //建立连接
    private static Jedis jedis = null;

    public static Jedis setConection() {
        if (jedis == null) {
             jedis = new Jedis("162.14.117.216", 6379);//ip地址 和端口
            jedis.auth("");//密码
            jedis.select(0);//选择的数据库
        }
        return jedis;
    }
    //操作数据库
    public static void test() {
        Jedis jedis = setConection();
        System.out.println(jedis.get("age"));//获取字符串类型的数据
        System.out.println(jedis.get("user:1"));//获取以json格式存储的数据
        System.out.println(jedis.hget("user:3", "name"));//以hash表存储的数据   user:3的name字段

        Set<String> set = jedis.zrevrange("stu", 0, 2);//获取SortedSet中 成绩前三名的姓名
        for (String s : set) {
            System.out.println(s);
        }
        close();
    }

    //释放资源
    public static void close() {
        if (jedis != null)
            jedis.close();
    }

    public static void main(String[] args) {
        test();

    }

Jedis连接池

jedis本身是线程不安全的,而且频繁创建和销毁线程会有巨大的损耗,使用了连接池来存储线程,实现线程复用

public class JediesPoolFactory {
    private static final JedisPool jedisPool;

    static {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();//创建连接池对象
        jedisPoolConfig.setMaxTotal(5);//最大连接数量
        jedisPoolConfig.setMaxIdle(2);//最大空闲连接数目
        jedisPoolConfig.setMaxWaitMillis(200);//最大等待时间
        jedisPool = new JedisPool(jedisPoolConfig, "162.14.117.216", 6379, 1000, "");
//jedisPoolConfig对象  IP 端口  超时等待时间 密码

    }

    public static Jedis getResource() {
//返回Jedis对象
        return jedisPool.getResource();
    }
}

SpringDataRedis

SpringData是Spring中进行数据整合的模块,包含对各种数据库的数据操作,其中对redis的集成模块是SpringDataRedis

1、 创建SpringBoot项目

2、配置文件 application.properties文件

#---------------------------------
# Redis数据库索引(默认为0)
spring.redis.database=0 
# Redis服务器地址
spring.redis.host=localhost
# Redis服务器连接端口
spring.redis.port=6379 
# Redis服务器连接密码(默认为空)
spring.redis.password=
#连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8 
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1 
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=8 
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0 
# 连接超时时间(毫秒)
spring.redis.timeout=1000
#---------------------------------

 3、使用

@SpringBootTest
public class Redis {

    //1、注入RedisTemplate  实现操作
    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void test() {
        redisTemplate.opsForValue().set("age", 9);
        System.out.println(redisTemplate.opsForValue().get("age"));//对字符串类型数据操作
    }
}

序列化问题

执行以下代码

    redisTemplate.opsForValue().set("name", "七七");

在服务器上获取并没有这个记录

 但是使用keys *查看所有的key,这里存在乱码,但是仍然发现是加入了一段信息+name的key

 在客户端查看是这样的

 这是因为发生了序列化

redisTemplate.opsForValue().set()方法的两个参数类型都是object,因此传入的name和七七,都被当做了java的对象,而redisTemplate底层的处理方式就是利用jdk的序列化工具ObjectOutputStream进行序列化

 

 在set方法中将内容转换为字节,最终使用的就是ObjectOutputStream转换的

 因此,最终name和key都被序列化了,最终存放的是

 同理,在调用get时,参数key也被序列化,因此获取到的都是null

解决办法

1、StringRedisTemplate继承RedisTemplate,StringRedisTemplate只能管理StringRedisTemplate里面的数据,RedisTemplate只能管理RedisTemplate中的数据。可以使用StringRedisTemplate进行字符串处理

 //1、注入RedisTemplate  实现操作
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Test
    public void test() {
        redisTemplate.opsForValue().set("name", "七七");
        System.out.println(redisTemplate.opsForValue().get("name"));//对字符串类型数据操作
    }

 2、自定义RedisTemplate的序列化方式


@Configuration
public class RedisConfig {

    //创建获取 redisTemplate对象的方法

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {

        //1、创建redisTemplate对象
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
        //2、设置连接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //3、设置json序列化工具
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        //引入jaskson库,实现json格式和java对象的转换
        ObjectMapper objectMapper = new ObjectMapper();
        //setVisibility 设置对象映射器的可见性规则
        //PropertyAccessor 是属性访问器  所有Spring创建的Bean对象都使用该接口存取Bean属性值
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        //指定指定序列化输入类型
        //不指定时  那存储到redis里的数据将是没有类型的纯json,我们调用redis API获取到数据后,java解析将是一个LinkHashMap类型的key-value的数据结构,我们需要使用的话就要自行解析,这样增加了编程的复杂度。
        //[{"id":72,"uuid":"c4d7fc52-4096-4c79-81ef-32cb1b87fd28","type":2}]

        //指定之后  存储到redis里的数据将是有类型的json数据,例如:
        //["java.util.ArrayList",[{"@class":"com.model.app","id":72,"uuid":"c4d7fc52-4096-4c79-81ef-32cb1b87fd28","type":2}]]
        // 这样java获取到数据后,将会将数据自动转化为java.util.ArrayList和com.model.app,方便直接使用。
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);


        //4、设置key序列化
        redisTemplate.setKeySerializer(RedisSerializer.string());  //RedisSerializer.string()返回的是 StringRedisSerializer.UTF_8 这个常量
        redisTemplate.setHashKeySerializer(RedisSerializer.string());  //RedisSerializer.string()返回的是 StringRedisSerializer.UTF_8 这个常量
        //5、设置value序列化 (json格式  实际根据业务场景决定·)
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
     

        return redisTemplate;
    }
}

存入对象,会转为json格式 

@Data
@AllArgsConstructor//有参构造
@NoArgsConstructor//无参数构造
public class User {
    private String name;
    private Integer age;
}

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Test
    public void  saveUsertest(){

        User user=new User("张三",19);
        redisTemplate.opsForValue().set("user:6",user);

        System.out.println(redisTemplate.opsForValue().get("user:6"));

    }

 为了在反序列化时知道对象的类型,会将类的class类型存入数据库,造成额外的内存开销

但是对象的类型在反序列化时必须要用到,不将类的class类型存入数据库,就要求在业务处理时手动转换

   @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void  saveUsertest() throws JsonProcessingException {

        User user = new User("七七", 300);
        ObjectMapper objectMapper = new ObjectMapper();
        String value = objectMapper.writeValueAsString(user);//将对象转为字符串
        redisTemplate.opsForValue().set("user:7", value);

        value = (String) redisTemplate.opsForValue().get("user:7");
        user = objectMapper.readValue(value, User.class);
        System.out.println(user);

    }

 hash和sortedset结构

  @Test
    public void test() {
//        获取hash表类型的value
        redisTemplate.opsForHash().put("user:3","age",18);
        redisTemplate.opsForHash().put("user:3","id",3);
        redisTemplate.opsForHash().put("user:3","name","七七");
        Map<Object, Object> map = redisTemplate.opsForHash().entries("user:3");
        for (Map.Entry<Object, Object> entry : map.entrySet()) {
            System.out.print(entry.getKey() + "  " + entry.getValue());
            System.out.println();
        }
        System.out.println("-----------");

      //  "jack",85, "LUCY",89,"ROSE",82, "TOM",95 , "JERRY",78 , "AMY",82 , "MILES",86
        redisTemplate.opsForZSet().add("stu1",new User("jack",20),85 );
        redisTemplate.opsForZSet().add("stu1",new User("lucy",20),89 );
        redisTemplate.opsForZSet().add("stu1",new User("rose",20),82) ;
        redisTemplate.opsForZSet().add("stu1",new User("tom",20),95 );
        redisTemplate.opsForZSet().add("stu1",new User("jerry",20),78 );
        redisTemplate.opsForZSet().add("stu1",new User("amy",20),82 );
        redisTemplate.opsForZSet().add( "stu1",new User("miles",20),86);
        //获取SortedSet 成绩前三名  "TOM",95  "LUCY",89   "MILES",86
        Set<Object> set = redisTemplate.opsForZSet().reverseRange("stu1", 0, 2);
        for (Object s : set) {
            System.out.println(s);
        }
    }

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值