篇章六 数据库操作(一)

目录

1.引入数据库

1.1 选择数据库

1.SQLite:

2.如何在Java中使用SQLite数据库

3.配置文件 application.yaml

url:jdbc:sqlite:./data/meta.db

1.2 建库建表

1.建库

2.建表

2.1 设计数据库表

2.2 建表时机的讨论

2.3 MyBatis基本使用流程

2.4 argument如何存到数据库中

1.3 实现数据库插入和删除

1.4 创建DataBaseManager

1.初始化:


1.引入数据库

在硬盘中管理Broker Server中的核心概念:

1.文件(消息)

2.数据库(交换机、队列、绑定)

1.1 选择数据库

因为 MySQL数据库本身比较重量(客户端——服务器结构 的程序)。本项目为了方便,简化环境,采用了更轻量的数据库SQLite

1.SQLite:

1.应用也非常广泛。在一些性能不高的设备上是使用数据库时的首选,比如移动端和嵌入式设备。Android 系统内置的数据库就是 SQLite。

2.一个完整的SQLite数据库,只是一个单独的可执行文件(不到1M),而且SQLite是一个本地的数据库,这个数据库相当于直接操纵本地的硬盘文件。

2.如何在Java中使用SQLite数据库

不用额外安装,直接使用maven这个项目管理工具,把SQLite的依赖引入即可(会自动加载jar包和动态库文件)

3.配置文件 application.yaml

spring:
  datasource:
    url: jdbc:sqlite:./data/meta.db
    username:
    password:
    driver-class-name: org.sqlite.JDBC

mybatis:
  mapper-locations: classpath:mapper/**Mapper.xml

url:jdbc:sqlite:./data/meta.db

这里采用了相对路径,那么必须明确 “基准路径” (“工作路径”)

1.如果是在 IDEA中直接运行程序,此时的工作路径就是当前项目所在的路径

2.如果是通过 java -jar 方式运行程序,此时你在哪个目录下工作,哪个目录就是工作路径

SQLite虽然和MySQL不太一样,但是都可以通过Mybatis这样的框架来使用

1.2 建库建表

1.建库

在SQLite中,数据库文件就是数据库,当把上述的配置和依赖都准备好后,程序启动,就会自动建库。

2.建表

2.1 设计数据库表

对照以前文章的 核心类很容易就可以把表设计出来。

2.2 建表时机的讨论

以往写程序,比如博客系统等,都是先把数据库的表都建好(把建库建表语句写到一个.sql文件中,需要建表的时候直接复制,到mysql客户端执行即可),然后再启动服务器。

但是,之前的程序就部署一次即可,不会反复操作,但是此项目可能会涉及到反复部署多次,所以简化部署步骤至关重要。很显然我们期望通过代码自动的完成建表操作。

2.3 MyBatis基本使用流程

1.创建一个 interface,描述有哪些方法要给 Java 代码使用

2.创建对应的xml,通过xml来实现上述的 interface 中的抽象方法

例如:

interface:

package com.xj.mq.mqserver.mapper;

import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface MetaMapper {
    // 提供三个核心建表方法
    void createExchangeTable();
    void createQueueTable();
    void createBindingTable();
}

 xml:


        create table if not exists exchange(
            name varchar(50) primary key,
            exchangeType int,
            durable boolean,
            autoDelete boolean,
            arguments varchar(1024)
        );
    
2.4 argument如何存到数据库中

为了把这个 auguments 存到数据库中, 就需要把 Map 转成 Json 格式的字符串

1.关键要点:

        MyBatis 往数据库中写数据时,会自动调用到对象的 getter 和 setter 方法

比如:MyBatis往数据库中写数据,就会调用对象的 getter方法,拿到属性的值,再往数据库中写。如果这个过程中,让getArguments 得到的结果是 String类型的,此时,就可以直接把这个数据写到数据库了。

2.改造 getArguments 方法

public String getArguments() {
        // 把当前arguments参数, 从Map转成String(JSON)
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            return objectMapper.writeValueAsString(arguments);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        // 代码异常时, 返回一个空的Json字符串就可以
        return "{}";
    }

3.改造 setArguments 方法

    public void setArguments(String argumentsJson) {

        ObjectMapper objectMapper = new ObjectMapper();
        try {
            this.arguments = objectMapper.readValue(argumentsJson, new TypeReference>() {});
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }

参数理解:objectMapper.readValue的第二个参数的含义

1.第二个参数,用来描述当前Json字符串要转成Java对象是什么类型。

2.如果是个简单类型,直接使用对应类型的类对象即可

3.如果是集合这种复杂的类型,可以使用 TypeReference 匿名内部类对象,来描述复杂类型的具体信息。(通过泛型参数来描述)

1.3 实现数据库插入和删除

这个和上述的建表差不多:

interface:

 // 针对上述三个基本概念 进行插入和删除
    void insertExchange(Exchange exchange);
    void deleteExchange(String exchangeName);
    void insertQueue(MessageQueue messageQueue);
    void deleteQueue(String queueName);
    void insertBinding(Binding binding);
    void deleteBinding(Binding binding);

xml:


        insert into exchange values(#{name}, #{exchangeType}, #{durable}, #{autoDelete}, #{arguments});
    

    
        delete from exchange where name = #{exchangeName}
    

    
        insert into queue values(#{name}, #{durable}, #{exclusive}, #{autoDelete}, #{arguments});
    

    
        delete from queue where name = #{queueName}
    

    
        insert into binding values(#{exchangeName}, #{queueName}, #{bindingKey});
    


    
        delete from binding where exchangeName = #{exchangeName} and queueName = #{queueName};
    

接口理解:void deleteQueue(Binding binding)

1.对于交换机和队列两个表,由于使用 name作为主键,直接按照name删除即可

2.对于绑定来说,此时没有主键,删除操作,其实是针对 exchangeName 和 queueName两个维度进行筛选。

1.4 创建DataBaseManager

写一个类来整合上述的数据库操作:

1.初始化:

一般谈到初始化,会使用构造方法,但是一般不会涉及到业务逻辑,只是初始化类的属性。

此处的初始化带有业务逻辑所以还是用一个普通的方法,单拎出来手动调用比较好。

package com.xj.mq.mqserver.datacenter;

import com.xj.mq.MqApplication;
import com.xj.mq.mqserver.core.Binding;
import com.xj.mq.mqserver.core.Exchange;
import com.xj.mq.mqserver.core.ExchangeType;
import com.xj.mq.mqserver.core.MessageQueue;
import com.xj.mq.mqserver.mapper.MetaMapper;

import java.io.File;
import java.util.List;
import java.util.Queue;

/**
 * Created with IntelliJ IDEA
 * Description 整合数据库操作
 *              进一步封装 如果不用MyBatis 不用改变此类的接口 只需改变内部的实现
 * User: 王杰
 * Date: 2025-05-14
 * Time: 23:49
 */
public class DataBaseManager {
    // 要从 Spring 中拿到现成的对象
    private MetaMapper metaMapper;

    public void init() {
        // 手动的获取到 MetaMapper
        metaMapper = MqApplication.context.getBean(MetaMapper.class);

        if (!checkDBExists()) {
            // 数据库不存在 建库建表
            // 先创建一个 data 目录
            File file = new File("./data");
            file.mkdirs();
            // 创建数据表
            createTable();
            // 插入默认数据
            createDefaultData();
            System.out.println("[DataBaseManager] 数据库初始化完成");
        }else {
            // 数据库已经存在 什么都不做
            System.out.println("[DataBaseManager] 数据库已存在");
        }
    }

    // 删除数据库
    public void deleteDB() {
        File file = new File("./data/meta.db");
        boolean ret = file.delete();
        if (ret) {
            System.out.println("[DataBaseManager] 删除数据库文件成功!");
        } else {
            System.out.println("[DataBaseManager] 删除数据库文件失败!");
        }

        File dataDir = new File("./data");
        // 使用 delete 删除目录的时候 目录必须是空的
        ret = dataDir.delete();
        if (ret) {
            System.out.println("[DataBaseManager] 删除数据库目录成功!");
        } else {
            System.out.println("[DataBaseManager] 删除数据库目录失败!");
        }
    }



    // 判断数据库是否存在
    private boolean checkDBExists() {
        File file = new File("./data/meta.db");
        if (file.exists()) {
            return true;
        }
        return false;
    }

    // 建表
    // 建库操作并不需要手动执行(不需要手动创建meta.db文件,MyBatis帮我们完成了)
    private void createTable() {
        metaMapper.createExchangeTable();
        metaMapper.createQueueTable();
        metaMapper.createBindingTable();
        System.out.println("[DataBaseManager] 创建表完成!");
    }
}

数据库的初始化

数据库已经存在了,不做任何操作

如果数据库不存在,创建库,创建表,构造默认数据

(自动的:现在把 Broker Server 部署到一个新的服务器上,启动就会自动建库建表)

1.建库建表:

执行metaMapper接口中的放啊发即可

2.插入一些默认数据

构造一个默认的Exchange即可

建库操作:为什么不需要手动创建meta.db文件?

        首次执行这里的数据库操作的时候,发现没有数据库文件meta.db,Mybatis就会帮我们自动的创建出来。

你可能感兴趣的:(项目_模拟实现消息队列,数据库,SQLite,MyBatis,Java)