Comparação entre armazenamento serializado de classe e armazenamento nativo de classe

Comparação entre armazenamento serializado de classe e armazenamento nativo de classe

 

        A serialização Java é converter um objeto em uma string de matrizes de bytes binários e atingir o objetivo de persistência salvando ou transferindo esses dados de bytes. A essência da serialização é salvar as informações do estado atual do objeto e não há necessidade de salvar as informações estruturais completas.

        O armazenamento nativo de classes Java é mapear objetos para o relacionamento do banco de dados. Uma classe de entidade corresponde a uma tabela no banco de dados e variáveis ​​de membro na classe correspondem a campos no banco de dados. O objetivo da persistência de dados é alcançado por meio do contêiner do banco de dados.

Ambos os dois métodos acima podem atingir o objetivo de persistência de dados, então há alguma diferença de desempenho entre os dois?

        Faremos um experimento comparativo para verificar se existe diferença de desempenho entre as duas, projetar uma classe Aluno com 12 atributos e implementar uma interface serializável, e projetar sua tabela de banco de dados correspondente e tabela para armazenamento de sua serialização, respectivamente. Observe a diferença em eficiência de tempo e eficiência de espaço entre os dois durante o processo de acesso aos registros do banco de dados.

Classe do aluno que implementa a interface de serialização


import java.io.Serializable;
import java.util.Date;

/*
 * 实现可序列化接口
 */
public class Student implements Serializable{
    private Integer id;

    private String name;

    private int age;

    private int gender;

    private String dept;

    private String tel;

    private String email;

    private String hobby;

    private String school;

    private double wallet;

    private int zodiac;

    private String address;

    public Student() {
    }

    public Student(Integer id, String name, int age, int gender, String dept, String tel, String email, String hobby, String school, double wallet, int zodiac, String address) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.dept = dept;
        this.tel = tel;
        this.email = email;
        this.hobby = hobby;
        this.school = school;
        this.wallet = wallet;
        this.zodiac = zodiac;
        this.address = address;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    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 int getGender() {
        return gender;
    }

    public void setGender(int gender) {
        this.gender = gender;
    }

    public String getDept() {
        return dept;
    }

    public void setDept(String dept) {
        this.dept = dept;
    }

    public String getTel() {
        return tel;
    }

    public void setTel(String tel) {
        this.tel = tel;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getHobby() {
        return hobby;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }

    public String getSchool() {
        return school;
    }

    public void setSchool(String school) {
        this.school = school;
    }

    public double getWallet() {
        return wallet;
    }

    public void setWallet(double wallet) {
        this.wallet = wallet;
    }

    public int getZodiac() {
        return zodiac;
    }

    public void setZodiac(int zodiac) {
        this.zodiac = zodiac;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", gender=" + gender +
                ", dept='" + dept + '\'' +
                ", tel='" + tel + '\'' +
                ", email='" + email + '\'' +
                ", hobby='" + hobby + '\'' +
                ", school='" + school + '\'' +
                ", wallet=" + wallet +
                ", zodiac=" + zodiac +
                ", address='" + address + '\'' +
                '}';
    }
}

Estrutura da tabela do aluno para armazenar classes de entidade

create table if not exists student (
	id int primary key,
	name varchar(10),
	age int,
	gender int,
	dept varchar(10) not null,
	tel varchar(11) unique,
	email varchar(18) unique,
	hobby varchar(10),
	school varchar(10) not null,
	wallet double(10,2),
	zodiac int,
	address varchar(20)
);

Armazenar estrutura de tabela de objeto serializado

create table if not exists objtest(
    id int primary key,
    obj blob not null
);

        

        Projete a classe DBHelper para implementar a operação do pool de conexão de banco de dados. Suas funções incluem configuração do pool de conexão de dados, reciclagem, inserção de tabela de banco de dados, consulta de tabela de banco de dados, esvaziamento de tabela de banco de dados e retorno do espaço ocupado pela tabela na memória.

        

Classe DBHelper

        Configuração do pool de conexões do banco de dados

public class DBHelper {
    private static Connection conn;
    private static PreparedStatement pres;
    private static ResultSet rs;
    private static ResourceBundle bundle = ResourceBundle.getBundle("jdbc");

    static {
        try {
            Class.forName(bundle.getString("Driver"));
            String url = bundle.getString("url");
            String user = bundle.getString("user");
            String password = bundle.getString("password");

            conn = DriverManager.getConnection(url, user, password);
            if (conn != null) {
                System.out.println("数据库连接成功");
            } else System.out.println("数据库连接失败");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

        Reciclagem do pool de conexão do banco de dados

public static void free(Connection conn, PreparedStatement pres, ResultSet rs) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        if (pres != null) {
            try {
                pres.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }

        Armazenamento serializado do objeto do aluno

public static void save(List<Student> students){
        long startTime = System.currentTimeMillis();
        String sql = "insert into objtest(obj) values(?)";
        try {
            pres=conn.prepareStatement(sql);
            for(int i = 0; i < students.size(); i ++){
                pres.setObject(1, students.get(i));
                pres.addBatch();
            }
            pres.executeBatch();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            free(conn, pres, null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("序列化存储运行时间:" + (endTime - startTime));
    }

        Consulta de serialização de objeto do aluno, desserialização

public static List<Student> read(){
        long startTime = System.currentTimeMillis();
        List<Student> list = new ArrayList<Student>();
        String sql="select obj from objtest";

        try {
            pres = conn.prepareStatement(sql);

            rs = pres.executeQuery();
            while(rs.next()){

                Blob blob = rs.getBlob(1);
                InputStream is = blob.getBinaryStream();
                BufferedInputStream buffer = new BufferedInputStream(is);

                byte[] buff = new byte[(int) blob.length()];
                while((buffer.read(buff, 0, buff.length)) != -1) {
                    ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(buff));
                    Student student = (Student) in.readObject();
                    list.add(student);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            free(conn, pres, rs);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("序列化读取运行时间:" + (endTime - startTime));
        return list;
    }

        Armazenamento nativo do objeto do aluno

public static void saveStudent(List<Student> students) {
        long startTime = System.currentTimeMillis();
        String sql = "insert into student(id, name, age, gender, dept, tel, email, hobby, school, wallet, zodiac, address) values (?,?,?,?,?,?,?,?,?,?,?,?)";
        try {
            pres = conn.prepareStatement(sql);
            for (Student student : students) {
                pres.setInt(1, student.getId());
                pres.setString(2, student.getName());
                pres.setInt(3, student.getAge());
                pres.setInt(4, student.getGender());
                pres.setString(5, student.getDept());
                pres.setString(6, student.getTel());
                pres.setString(7, student.getEmail());
                pres.setString(8, student.getHobby());
                pres.setString(9, student.getSchool());
                pres.setDouble(10, student.getWallet());
                pres.setInt(11, student.getZodiac());
                pres.setString(12, student.getAddress());
                pres.addBatch();
            }
            pres.executeBatch();

        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("直接存储运行时间:" + (endTime - startTime) + "ms");
    }

        Consulta nativa do objeto do aluno

public static List<Student> readStudent() {
        long startTime = System.currentTimeMillis();
        List<Student> list = new ArrayList<Student>();
        String sql = "select * from student";

        try {
            pres = conn.prepareStatement(sql);
            rs = pres.executeQuery();
            while (rs.next()) {
                Integer id = rs.getInt("id");
                String name = rs.getString("name");
                int age = rs.getInt("age");
                int gender = rs.getInt("gender");
                String dept = rs.getString("dept");
                String tel = rs.getString("tel");
                String email = rs.getString("email");
                String hobby = rs.getString("hobby");
                String school = rs.getString("school");
                double wallet = rs.getDouble("wallet");
                int zodiac = rs.getInt("zodiac");
                String address = rs.getString("address");
                Student student = new Student(id, name, age, gender, dept, tel, email, hobby, school, wallet, zodiac, address);
                list.add(student);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("直接读取运行时间:" + (endTime - startTime) + "ms");
        return list;
    }

        Limpar a tabela do banco de dados

public static void cleanTable() {
        String sql1 = "truncate table student";
        String sql2 = "truncate table objtest";
        try {
            pres = conn.prepareStatement(sql1);
            pres.executeUpdate();
            pres = conn.prepareStatement(sql2);
            pres.executeUpdate();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            free(conn, pres, null);
        }
    }

        Espaço de memória ocupado por registros de consulta

public static void getMemory(String tableName) {
        double memory = 0;
        int rows = 0;
        String sql = "SELECT TABLE_NAME,DATA_LENGTH+INDEX_LENGTH memory,TABLE_ROWS FROM TABLES WHERE TABLE_SCHEMA='jdbc' AND TABLE_NAME=?";
        try {
            pres = conn.prepareStatement(sql);
            pres.setString(1, tableName);
            rs = pres.executeQuery();
            if (rs.next()) {
                memory = rs.getDouble("memory");
                rows = rs.getInt("TABLE_ROWS");
            }
            System.out.println("表中记录数: " + rows + " 占用内存空间:" + memory / 1024 + "KB");
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

        

procedimento experimental

        Projete a classe de teste Test para inserir e consultar repetidamente as classes de entidade do aluno com diferentes números de registros e conduza um experimento de controle observando os timestamps consumidos no processo de armazenamento e consulta no banco de dados.

        

amostra experimental

        Defina o número de registros em cinco grupos como 1, 5, 200, 1.000, 5.000 e 10.000, repita o armazenamento e a consulta 5 vezes e obtenha o valor médio do tempo de execução e do espaço de memória.

        

        classe de teste

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Test {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int count = scanner.nextInt();
        List<Student> list = new ArrayList<>();
        DBHelper.cleanTable(); // 清空数据库表
        for (int i = 1; i <= count; i++) {
            list.add(new Student(i, "zhangsan", 18, 1, "计算机系", "10086", "[email protected]", "basketball", "温州大学", 3.8, 5, "温州大学计算机与人工智能学院"));
        }
        System.out.println("记录数为 "+ count +"条时:");
        DBHelper.save(list); // 学生类序列化存储
        DBHelper.saveStudent(list); // 学生类对象存储
        DBHelper.read(); // 学生类序列化查询
        DBHelper.readStudent(); // 学生类对象查询
    }
}

        

Resultados experimentais 

Armazenando dados
Número de registros/artigo Nativo (tempo médio/ms) Serialização (tempo médio/ms)
1 10.8 27.2
200 666,4 734.2
1000 3038.4 3211.8
5000 14080.8 14384.2
10000 27909.4 28020.4
Consultar dados
Número de registros/artigo Nativo (tempo médio/ms) Serialização (tempo médio/ms)
1 4.6 24,0
200 48.2 95,0
1000 120.2 195,6
5000 226,0 440,6
10000 320,4 759,4

espaço de memória
Número de registros/artigo Nativo (tamanho da memória/kb) Serialização (tamanho da memória/kb)
1 16 16
200 64 64
1000 192 496
5000 1552 2576
10000 2576 5648

           Através de experimentos, verifica-se que o tempo de armazenamento dos dados serializados é semelhante ao do armazenamento original à medida que o número de registros aumenta, mas o tempo gasto no processo de consulta é cerca de duas vezes o da consulta original; em termos de memória espaço, com o aumento do número de registros, a memória ocupada pelos dados serializados também aumenta. Pode-se ver que, para o armazenamento persistente de objetos de entidade, o armazenamento nativo tem melhor desempenho em eficiência do que o armazenamento serializado.

        As possíveis razões para a diferença na eficiência da serialização são:

        1. Leva um certo tempo para serializar e desserializar a própria classe;

        2. Os dados serializados são um fluxo binário, que ocupa um espaço maior (cerca de 412 bytes/item) e consome mais tempo durante a consulta ao banco de dados e o retorno entre domínios após a consulta.

 opinião pessoal

        Para os dois métodos de armazenamento persistente, é mais claro usar diretamente o mapeamento entre classes de entidade e tabelas de banco de dados, o que é conveniente para executar várias operações de consulta, modificação e exclusão e pode obter facilmente as condições de consulta necessárias; em termos de segurança de dados, não O mapeamento da classe de entidade criptografada na tabela do banco de dados será exibido na forma de texto simples e o objeto é serializado para obter um conjunto de fluxos de bytes incompreensíveis, mas ainda pode ser desserializado e restaurado ao original na JVM ambiente.Existe forma. No entanto, na comunicação entre processos, a transferência de objetos entre os processos é realizada e o fluxo de bytes gerado após a serialização pode mostrar as características de alta eficiência, conveniência e durabilidade durante a transmissão.

 artigo de referência

(45 mensagens) Após a versão do MySQL8, o número de linhas na tabela do sistema information_schema.tables e o número de linhas na tabela de dados real são tratados incorretamente_Blog de AllenLeungX-Blog CSDN

Acho que você gosta

Origin blog.csdn.net/qq_43500084/article/details/127639090
Recomendado
Clasificación