一文彻底搞懂序列化和反序列化

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 一文彻底搞懂序列化和反序列化

背景

最近项目中要按照对象方式进行存取,使用时再拿出来,于是我们就要学习序列化和反序列化的相关知识。

基于我们的项目,按照课表进行推课的时候,课表中当前课程结束的时候,将执行的颗粒存到redis中。

步骤

概念

序列化和反序列化是计算机科学中用于数据存储和传输的重要概念。

序列化(Serialization)

是将数据结构或对象转换成一种可存储或可传输格式的过程。在序列化后,数据可以被写入文件、发送到网络或存储在数据库中,以便在需要时可以再次还原成原始的数据结构或对象。序列化的过程通常涉及将数据转换成字节流或类似的格式,使其能够在不同平台和编程语言之间进行传输和交换。

反序列化(Deserialization)

是序列化的逆过程,即将序列化后的数据重新还原成原始的数据结构或对象。反序列化是从文件、网络数据或数据库中读取序列化的数据,并将其转换回原始形式,以便在程序中进行使用和操作。

使用场景

序列化和反序列化在许多场景中都非常有用,例如:

数据存储:将程序中的数据保存到文件或数据库中,以便在以后重新加载和使用。

网络通信:在网络上传输数据时,需要将数据序列化为字节流,以便在接收端进行反序列化。

分布式系统:在分布式系统中,不同计算节点之间需要通过序列化和反序列化来交换数据。

进程间通信:不同进程之间通信时,数据需要在序列化和反序列化之间进行转换。

常见的序列化格式包括 JSON(JavaScript Object Notation)、XML(eXtensible Markup Language)、Protocol Buffers、MessagePack等。每种格式有其优势和适用场景,选择合适的序列化格式取决于具体的应用需求。

理解原理小Demo(可以理解成编码解码,很简单的)

import java.io.*;
public class Serialization {
    private static final File SAVE_FILE = new File("D:" + File.separator + "demo.Class");
    public static void saveObject(Object object) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(SAVE_FILE));
        oos.writeObject(object); // 序列化
        oos.close();
    }
    public static Object loadObject() throws Exception {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(SAVE_FILE));
        Object obj = ois.readObject(); // 反序列化
        ois.close();
        return obj;
    }
    public static void main(String[] args) throws Exception {
        saveObject(new Class(new Person("p",11),"class",12));// 序列化
        Class c = (Class)loadObject();
        System.out.println(c); // 反序列化
    }
    public static class Person implements Serializable {
        private String name;
        private int age;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    public static class Class implements Serializable{
        private Person person;
        private String name;
        private int age;
        public Person getPerson() {
            return person;
        }
        public void setPerson(Person person) {
            this.person = person;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        @Override
        public String toString() {
            return "Class{" +
                    "person=" + person +
                    ", name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
        public Class(Person person) {
            this.person = person;
        }
        public Class(Person person, String name, int age) {
            this.person = person;
            this.name = name;
            this.age = age;
        }
    }
}

可以通过打断点的方式查看对象的展示情况

将内存中的对象通过序列化的方式存储到本地的某个文件中

然后调用另外一个方法从本地文件中拿到对象放置到内存中

这样我们就了解了序列化和反序列的概念,下面看看在redis是如何实现序列化和反序列化的吧。

使用redis步骤

建立springboot项目

引入坐标

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

建类

在这里插入代码片
package com.example.redis.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
    /**
     * RedisTemplate配置
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
        // 设置序列化
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // 配置redisTemplate
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(lettuceConnectionFactory);
        RedisSerializer<?> stringSerializer = new StringRedisSerializer();
        // key序列化
        redisTemplate.setKeySerializer(stringSerializer);
        // value序列化
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        // Hash key序列化
        redisTemplate.setHashKeySerializer(stringSerializer);
        // Hash value序列化
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}
server:
  port: 8081
spring:
  redis:
    host: **redis.***d.tech
    port: 6379
    password: ***
    database: 0
    timeout: 300000ms  #连接超时
    jedis:
      pool:
        max-active: 8  #连接池最大的连接数
        max-wait: -1ms  #连接池最大的阻塞等待时间(负值表示没有限制)
        max-idle: 500  #连接池最大的空闲连接
package com.example.redis.Entity;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
public class UserInfo implements Serializable {
    /**
     * id
     */
    private Integer id;
    /**
     * 姓名
     */
    private String name;
    /**
     * 创建时间
     */
    private Date createTime;
}
package com.example.redis.utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
/**
 * @ClassName RedisUtils
 * @Description
 * @Author Lizhou
 * @Date 2020-10-22 10:10:10
 **/
@Slf4j
@Component
public class RedisUtils {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    /**
     * 根据key读取数据
     */
    public Object get(final String key) {
        if (StringUtils.isEmpty(key)) {
            return null;
        }
        try {
            return redisTemplate.opsForValue().get(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 写入数据
     */
    public boolean set(final String key, Object value) {
        if (StringUtils.isEmpty(key)) {
            return false;
        }
        try {
            redisTemplate.opsForValue().set(key, value);
            log.info("存入redis成功,key:{},value:{}", key, value);
            return true;
        } catch (Exception e) {
            log.error("存入redis失败,key:{},value:{}", key, value);
            e.printStackTrace();
        }
        return false;
    }
}
package com.example.redis;
import com.example.redis.Entity.UserInfo;
import com.example.redis.utils.RedisUtils;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Date;
@SpringBootTest
class RedisTestApplicationTests {
    @Autowired
    private RedisUtils redisUtil;
    @Test
    void contextLoads() {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setName("jack");
        userInfo.setCreateTime(new Date());
        // 放入redis
        redisUtil.set("user", userInfo);
        // 从redis中获取
        System.out.println("获取到数据:" + redisUtil.get("user"));
    }
}

根据key值查看redis中的值

简单介绍redis

Redis(Remote Dictionary Server)是一种开源的高性能键值存储数据库,它也被称为数据结构服务器,因为它支持多种灵活的数据结构。Redis以内存中的数据结构为基础,提供了快速、高效的数据存储和访问能力。它可以用作数据库、缓存、消息代理和排行榜等多种用途。

以下是 Redis 的一些主要特点:

键值存储:

Redis将数据存储为键值对,其中键是唯一的标识符,而值可以是字符串、哈希、列表、集合、有序集合等各种数据结构。

内存数据库:(因为我们是面向对象开发,所有就要使用内存数据库啦,因为要把对象存取来哦)

Redis的所有数据都存储在内存中,因此具有非常快的读写速度。但是,它也支持将数据持久化到磁盘,以便在重启后恢复数据。

丰富的数据结构:

Redis支持多种数据结构,如字符串、哈希表、列表(链表)、集合、有序集合等。这使得Redis在处理不同类型的数据时非常灵活和高效。

高性能:

由于数据存储在内存中,Redis能够实现非常高的读写速度。此外,它使用单线程模型来避免了多线程带来的竞争条件,使得其在单核系统上也能表现出色。

支持事务:

Redis支持简单的事务,你可以将多个命令放在一个事务中,然后一次性执行这些命令。在事务执行期间,其他客户端不会对其进行干扰。

发布/订阅:

Redis支持发布/订阅模式,允许客户端订阅一个或多个频道,当有消息发布到这些频道时,订阅的客户端将会收到相应的消息。

集群支持:

Redis支持将数据分布在多个节点上,从而实现高可用性和横向扩展。

轻量级:

Redis的代码库相对较小,没有复杂的依赖,因此非常轻量级且易于安装和部署。

Redis广泛应用于Web开发、缓存、会话存储、实时分析、消息队列等场景。由于其高性能和灵活性,Redis成为了许多应用架构中不可或缺的一部分。

总结

序列化在Redis中发挥着重要的作用,它使得数据可以被转换成一种便于存储和传输的格式,并可以通过网络进行传输。当数据需要被存储到Redis中时,通常需要先进行序列化,将数据转换成适合Redis存储的形式。而在从Redis中取出数据时,则需要进行反序列化,将序列化后的数据重新还原成原始的数据结构,以便在程序中进行使用和操作。

总之,序列化和反序列化是数据在存储和传输过程中的桥梁,而Redis作为高性能的键值存储数据库,则利用序列化机制来存储和操作数据,提供快速、灵活的数据存储和访问服务。通过将数据序列化后存储在Redis中,我们可以充分发挥Redis的优势,实现高效的数据处理和管理。


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
3月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
3月前
|
存储 开发框架 .NET
解锁SqlSugar新境界:利用Serialize.Linq实现Lambda表达式灵活序列化与反序列化,赋能动态数据查询新高度!
【8月更文挑战第3天】随着软件开发复杂度提升,数据查询的灵活性变得至关重要。SqlSugar作为一款轻量级、高性能的.NET ORM框架,简化了数据库操作。但在需要跨服务共享查询逻辑时,直接传递Lambda表达式不可行。这时,Serialize.Linq库大显身手,能将Linq表达式序列化为字符串,实现在不同服务间传输查询逻辑。结合使用SqlSugar和Serialize.Linq,不仅能够保持代码清晰,还能实现复杂的动态查询逻辑,极大地增强了应用程序的灵活性和可扩展性。
142 2
|
15天前
|
JSON 数据格式 索引
Python中序列化/反序列化JSON格式的数据
【11月更文挑战第4天】本文介绍了 Python 中使用 `json` 模块进行序列化和反序列化的操作。序列化是指将 Python 对象(如字典、列表)转换为 JSON 字符串,主要使用 `json.dumps` 方法。示例包括基本的字典和列表序列化,以及自定义类的序列化。反序列化则是将 JSON 字符串转换回 Python 对象,使用 `json.loads` 方法。文中还提供了具体的代码示例,展示了如何处理不同类型的 Python 对象。
|
25天前
|
存储 安全 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第22天】在Java的世界里,对象序列化和反序列化是数据持久化和网络传输的关键技术。本文将带你了解如何在Java中实现对象的序列化与反序列化,并探讨其背后的原理。通过实际代码示例,我们将一步步展示如何将复杂数据结构转换为字节流,以及如何将这些字节流还原为Java对象。文章还将讨论在使用序列化时应注意的安全性问题,以确保你的应用程序既高效又安全。
|
1月前
|
存储 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第9天】在Java的世界里,对象序列化是连接数据持久化与网络通信的桥梁。本文将深入探讨Java对象序列化的机制、实践方法及反序列化过程,通过代码示例揭示其背后的原理。从基础概念到高级应用,我们将一步步揭开序列化技术的神秘面纱,让读者能够掌握这一强大工具,以应对数据存储和传输的挑战。
|
1月前
|
存储 安全 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第3天】在Java编程的世界里,对象序列化与反序列化是实现数据持久化和网络传输的关键技术。本文将深入探讨Java序列化的原理、应用场景以及如何通过代码示例实现对象的序列化与反序列化过程。从基础概念到实践操作,我们将一步步揭示这一技术的魅力所在。
|
25天前
|
存储 缓存 NoSQL
一篇搞懂!Java对象序列化与反序列化的底层逻辑
本文介绍了Java中的序列化与反序列化,包括基本概念、应用场景、实现方式及注意事项。序列化是将对象转换为字节流,便于存储和传输;反序列化则是将字节流还原为对象。文中详细讲解了实现序列化的步骤,以及常见的反序列化失败原因和最佳实践。通过实例和代码示例,帮助读者更好地理解和应用这一重要技术。
24 0
|
2月前
|
JSON fastjson Java
niubility!即使JavaBean没有默认无参构造器,fastjson也可以反序列化。- - - - 阿里Fastjson反序列化源码分析
本文详细分析了 Fastjson 反序列化对象的源码(版本 fastjson-1.2.60),揭示了即使 JavaBean 沲有默认无参构造器,Fastjson 仍能正常反序列化的技术内幕。文章通过案例展示了 Fastjson 在不同构造器情况下的行为,并深入探讨了 `ParserConfig#getDeserializer` 方法的核心逻辑。此外,还介绍了 ASM 字节码技术的应用及其在反序列化过程中的角色。
77 10
|
2月前
|
存储 XML JSON
用示例说明序列化和反序列化
用示例说明序列化和反序列化
|
2月前
|
存储 Java 开发者
Java编程中的对象序列化与反序列化
【9月更文挑战第20天】在本文中,我们将探索Java编程中的一个核心概念——对象序列化与反序列化。通过简单易懂的语言和直观的代码示例,你将学会如何将对象状态保存为字节流,以及如何从字节流恢复对象状态。这不仅有助于理解Java中的I/O机制,还能提升你的数据持久化能力。准备好让你的Java技能更上一层楼了吗?让我们开始吧!