目录
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.初始化:
在硬盘中管理Broker Server中的核心概念:
1.文件(消息)
2.数据库(交换机、队列、绑定)
因为 MySQL数据库本身比较重量(客户端——服务器结构 的程序)。本项目为了方便,简化环境,采用了更轻量的数据库SQLite
1.应用也非常广泛。在一些性能不高的设备上是使用数据库时的首选,比如移动端和嵌入式设备。Android 系统内置的数据库就是 SQLite。
2.一个完整的SQLite数据库,只是一个单独的可执行文件(不到1M),而且SQLite是一个本地的数据库,这个数据库相当于直接操纵本地的硬盘文件。
不用额外安装,直接使用maven这个项目管理工具,把SQLite的依赖引入即可(会自动加载jar包和动态库文件)
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这样的框架来使用
在SQLite中,数据库文件就是数据库,当把上述的配置和依赖都准备好后,程序启动,就会自动建库。
对照以前文章的 核心类很容易就可以把表设计出来。
以往写程序,比如博客系统等,都是先把数据库的表都建好(把建库建表语句写到一个.sql文件中,需要建表的时候直接复制,到mysql客户端执行即可),然后再启动服务器。
但是,之前的程序就部署一次即可,不会反复操作,但是此项目可能会涉及到反复部署多次,所以简化部署步骤至关重要。很显然我们期望通过代码自动的完成建表操作。
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)
);
为了把这个 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 匿名内部类对象,来描述复杂类型的具体信息。(通过泛型参数来描述)
这个和上述的建表差不多:
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两个维度进行筛选。
写一个类来整合上述的数据库操作:
一般谈到初始化,会使用构造方法,但是一般不会涉及到业务逻辑,只是初始化类的属性。
此处的初始化带有业务逻辑所以还是用一个普通的方法,单拎出来手动调用比较好。
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就会帮我们自动的创建出来。