这里写自定义目录标题
- 前言
- 数据表的插入删除操作
- 关于实现接口类的几个注意实现
- 实现封装
- 创建DataBaseManager 类
- 另一种获取Bean对象的方式
- 对数据库进行单元测试
前言
上一篇博客, 我们将消息队列的实体类创建完毕了, 并且还写了一些关于数据库的操作, 接下来我们继续进行关于数据库的操作
数据表的插入删除操作
上一篇博客, 写了建立三个表的操作, 建立了表之后, 我们应该将对应的插入,查询,查找操作也同样添加进去
步骤1 : 在接口类MateMapper中创建关于插入查询, 删除的接口
// 下面是关于这些表的插入与删除操作
void insertExchange(Exchange exchange);
List<Exchange> selectAllExchanges();
void deleteExchange(String exchangeName);
void insertQueue(MSGQueue queue);
List<MSGQueue> selectAllQueues();
void deleteQueue(String queueName);
void insertBinding(Binding binding);
List<Binding> selectAllBindings();
void deleteBinding(Binding binding);
步骤2 : 在xml中实现相关的接口
这里给大家解释一下 parameterType 与 resultType 的区别
parameterType : 指的是传入参数的类型, 因为咱们不是传入基本的数据类型,而是传入一个对象, 所以需要设置一下, 里面的路径就是 对应的实体类
resultType : 指的是返回结果的类型, 一般是用在 select 查找方面
<insert id="insertExchange" parameterType="com.example.demo.mqServer.core.Exchange">
insert into exchange values( #{name},#{type},#{durable},#{autoDelete},#{arguments});
</insert>
<select id="selectAllExchanges" resultType="com.example.demo.mqServer.core.Exchange">
select * from exchange;
</select>
<delete id="deleteExchange" parameterType="java.lang.String">
delete from exchange where name = #{exchangeName};
</delete>
<insert id="insertQueue" parameterType="com.example.demo.mqServer.core.MSGQueue">
insert into queue values( #{name} , #{durable}, #{exclusive}, #{autoDelete} ,#{arguments});
</insert>
<select id="selectAllQueues" resultType="com.example.demo.mqServer.core.MSGQueue">
select * from queue;
</select>
<delete id="deleteQueue" parameterType="java.lang.String">
delete from queue where name = #{queueName};
</delete>
<insert id="insertBinding" parameterType="com.example.demo.mqServer.core.Binding">
insert into binding values( #{exchangeName},#{msgQueueName},#{bindingKey});
</insert>
<select id="selectAllBindings" resultType="com.example.demo.mqServer.core.Binding">
select * from binding;
</select>
<delete id="deleteBinding" parameterType="com.example.demo.mqServer.core.Binding">
delete from binding where exchangeName = #{exchangeName} and msgQueueName = #{msgQueueName};
</delete>
关于实现接口类的几个注意实现
- 不管是parameteType 还是 resultType 都要注意路径是否正确
- 注意SQL语句不要写错了
- 增删查改里面的 SQL 字段名 要与 实体类的相一致
实现封装
在写完上述的接口类 与 xml 后, 我们想要 创建一个类 ,来调用 接口类中的各种方法 , 并对数据库完成一些操作
创建DataBaseManager 类
在这个类中, 我们 需要完成对数据库的建库建表操作 , 并封装 一些关于表的增删查改方法(这里说一下, 因为我们使用的数据库是SQLite 是一个文件, 所以当调用建表操作的时候就自动建库了)
对于各种方法的介绍, 都写进代码里面了 ,自行阅读即可
package com.example.demo.mqServer.dataCenter;
import com.example.demo.MqApplication;
import com.example.demo.mqServer.core.Binding;
import com.example.demo.mqServer.core.Exchange;
import com.example.demo.mqServer.core.ExchangeType;
import com.example.demo.mqServer.core.MSGQueue;
import com.example.demo.mqServer.mapper.MateMapper;
import java.io.File;
import java.util.List;
public class DataBaseManager {
private MateMapper mateMapper;
// 针对数据库进行初始化
public void init() {
// 手动获取matemapper 对象
mateMapper = MqApplication.context.getBean(MateMapper.class);
// 手动的获取到 MetaMapper
if (!checkDBExists()) {
//如果数据库不存在,就进行建表操作
// 先创建一个data目录
File dataDir = new File("./data");
dataDir.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] 删除数据库目录失败!");
}
}
// 检查是否存在meta.db 文件
private boolean checkDBExists() {
File file = new File("./data/meta.db");
return file.exists();
}
// 这个方法用来建表.
// 建库操作并不需要手动执行. (不需要手动创建 meta.db 文件)
// 首次执行这里的数据库操作的时候, 就会自动的创建出 meta.db 文件来 (MyBatis 帮我们完成的)
private void createTable() {
mateMapper.createExchangeTable();
mateMapper.createQueueTable();
mateMapper.createBindingTable();
System.out.println("[DataBaseManager] 创建表完成!");
}
// 给数据库表中, 添加默认的数据.
// 此处主要是添加一个默认的交换机.
// RabbitMQ 里有一个这样的设定: 带有一个 匿名 的交换机, 类型是 DIRECT.
private void createDefaultData() {
// 先构建一个交换机
Exchange exchange = new Exchange();
exchange.setName("");
exchange.setType(ExchangeType.direct);
exchange.setDurable(true);
exchange.setAutoDelete(false);
mateMapper.insertExchange(exchange);
System.out.println("[DataBaseManager] 创建初始数据完成!");
}
public void insertExchange(Exchange exchange){
mateMapper.insertExchange(exchange);
}
public List<Exchange> selectAllExchanges(){
return mateMapper.selectAllExchanges();
}
public void deleteExchange(String exchangeName){
mateMapper.deleteExchange(exchangeName);
}
public void insertQueue(MSGQueue queue){
mateMapper.insertQueue(queue);
}
public List<MSGQueue> selectAllQueues(){
return mateMapper.selectAllQueues();
}
public void deleteQueue(String queueName){
mateMapper.deleteQueue(queueName);
}
public void insertBinding(Binding binding){
mateMapper.insertBinding(binding);
}
public List<Binding> selectAllBindings(){
return mateMapper.selectAllBindings();
}
public void deleteBinding(Binding binding){
mateMapper.deleteBinding(binding);
}
}
另一种获取Bean对象的方式
对DataBaseManager 类的 解释, 我们知道 想要 获取 Bean对象 一般情况下 我们使用的 @Autowired注解, 但是这个类 我们想要手动 来操作, 使用@Autowired 就在一开始就存入了 , 所以我们教大家另一种 获取Bean对象的方式
步骤1: 找到启动类 , 在启动类中添加一个静态成员
public static ConfigurableApplicationContext context;
步骤2: 使用context 等于 run方法结果
步骤3: 在DataBaseManager 中使用 context 来实现对象装配
mateMapper = MqApplication.context.getBean(MateMapper.class);
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class MqApplication {
// 在启动类创建一个静态成员, 用来手动的获取bean对象
public static ConfigurableApplicationContext context;
public static void main(String[] args) {
context = SpringApplication.run(MqApplication.class, args);
}
}
对数据库进行单元测试
但我们,每写完一个模块的时候, 我们就应该对该模块就行单元测试 ,
接下来我们对数据库进行单元测试
单元测试是在想要测试的类中点击Generate , 会出现一个Test ,点击Test
这个Test(安装Junit的插件-这里就不介绍了) , 然后选择你想要测试的方法,点击OK
会在Test包中生成对应的类 , 在这个类中加上@SpringBootTest 注解 ,就可以正常使用了
测试代码如下
package com.example.demo.mqServer.dataCenter;
import com.example.demo.MqApplication;
import com.example.demo.mqServer.core.Binding;
import com.example.demo.mqServer.core.Exchange;
import com.example.demo.mqServer.core.ExchangeType;
import com.example.demo.mqServer.core.MSGQueue;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
class DataBaseManagerTest {
private DataBaseManager dataBaseManager = new DataBaseManager();
// 接下来下面这里需要编写多个 方法 . 每个方法都是一个/一组单元测试用例.
// 还需要做一个准备工作. 需要写两个方法, 分别用于进行 "准备工作" 和 "收尾工作"
// 使用这个方法, 来执行准备工作. 每个用例执行前, 都要调用这个方法.
@BeforeEach
public void setUp() {
// 由于在 init 中, 需要通过 context 对象拿到 metaMapper 实例的.
// 所以就需要先把 context 对象给搞出来.
MqApplication.context = SpringApplication.run(MqApplication.class);
dataBaseManager.init();
}
// 使用这个方法, 来执行收尾工作. 每个用例执行后, 都要调用这个方法.
@AfterEach
public void tearDown() {
// 这里要进行的操作, 就是把数据库给清空~~ (把数据库文件, meta.db 直接删了就行了)
// 注意, 此处不能直接就删除, 而需要先关闭上述 context 对象!!
// 此处的 context 对象, 持有了 MetaMapper 的实例, MetaMapper 实例又打开了 meta.db 数据库文件.
// 如果 meta.db 被别人打开了, 此时的删除文件操作是不会成功的 (Windows 系统的限制, Linux 则没这个问题).
// 另一方面, 获取 context 操作, 会占用 8080 端口. 此处的 close 也是释放 8080.
MqApplication.context.close();
dataBaseManager.deleteDB();
}
@Test
public void testInitTable() {
// 由于 init 方法, 已经在上面 setUp 中调用过了. 直接在测试用例代码中, 检查当前的数据库状态即可.
// 直接从数据库中查询. 看数据是否符合预期.
// 查交换机表, 里面应该有一个数据(匿名的 exchange); 查队列表, 没有数据; 查绑定表, 没有数据.
List<Exchange> exchangeList = dataBaseManager.selectAllExchanges();
List<MSGQueue> queueList = dataBaseManager.selectAllQueues();
List<Binding> bindingList = dataBaseManager.selectAllBindings();
// 直接打印结果, 通过肉眼来检查结果, 固然也可以. 但是不优雅, 不方便.
// 更好的办法是使用断言.
// System.out.println(exchangeList.size());
// assertEquals 判定结果是不是相等.
// 注意这俩参数的顺序. 虽然比较相等, 谁在前谁在后, 无所谓.
// 但是 assertEquals 的形参, 第一个形参叫做 expected (预期的), 第二个形参叫做 actual (实际的)
Assertions.assertEquals(1, exchangeList.size());
Assertions.assertEquals("", exchangeList.get(0).getName());
Assertions.assertEquals(ExchangeType.direct, exchangeList.get(0).getType());
Assertions.assertEquals(0, queueList.size());
Assertions.assertEquals(0, bindingList.size());
}
private Exchange createExchange(String name){
Exchange exchange = new Exchange();
exchange.setName(name);
exchange.setAutoDelete(false);
exchange.setDurable(true);
exchange.setType(ExchangeType.fanout);
exchange.setArguments("aaa",1);
exchange.setArguments("bbb",2);
return exchange;
}
@Test
public void insertExchange() {
Exchange exchange =createExchange("testExchange");
dataBaseManager.insertExchange(exchange);
// 插入完毕之后, 查询结果
List<Exchange> exchangeList = dataBaseManager.selectAllExchanges();
Assertions.assertEquals(2, exchangeList.size());
Exchange newExchange = exchangeList.get(1);
Assertions.assertEquals("testExchange", newExchange.getName());
Assertions.assertEquals(ExchangeType.fanout, newExchange.getType());
Assertions.assertEquals(false, newExchange.isAutoDelete());
Assertions.assertEquals(true, newExchange.isDurable());
Assertions.assertEquals(1, newExchange.getArguments("aaa"));
Assertions.assertEquals(2, newExchange.getArguments("bbb"));
System.out.println("insertExchange测试成功");
}
@Test
public void testDeleteExchange() {
// 先构造一个交换机, 插入数据库; 然后再按照名字删除即可!
Exchange exchange =createExchange("testExchange");
dataBaseManager.insertExchange(exchange);
List<Exchange> exchangeList = dataBaseManager.selectAllExchanges();
Assertions.assertEquals(2, exchangeList.size());
Assertions.assertEquals("testExchange", exchangeList.get(1).getName());
// 进行删除操作
dataBaseManager.deleteExchange("testExchange");
// 再次查询
exchangeList = dataBaseManager.selectAllExchanges();
Assertions.assertEquals(1, exchangeList.size());
Assertions.assertEquals("", exchangeList.get(0).getName());
System.out.println("testDeleteExchange测试成功");
}
private MSGQueue createTestQueue(String queueName) {
MSGQueue queue = new MSGQueue();
queue.setName(queueName);
queue.setDurable(true);
queue.setAutoDelete(false);
queue.setExclusive(false);
queue.setArguments("aaa", 1);
queue.setArguments("bbb", 2);
return queue;
}
@Test
public void testInsertQueue() {
MSGQueue queue = createTestQueue("testQueue");
dataBaseManager.insertQueue(queue);
List<MSGQueue> queueList = dataBaseManager.selectAllQueues();
Assertions.assertEquals(1, queueList.size());
MSGQueue newQueue = queueList.get(0);
Assertions.assertEquals("testQueue", newQueue.getName());
Assertions.assertEquals(true, newQueue.isDurable());
Assertions.assertEquals(false, newQueue.isAutoDelete());
Assertions.assertEquals(false, newQueue.isExclusive());
Assertions.assertEquals(1, newQueue.getArguments("aaa"));
Assertions.assertEquals(2, newQueue.getArguments("bbb"));
System.out.println("testInsertQueue测试成功");
}
@Test
public void testDeleteQueue() {
MSGQueue queue = createTestQueue("testQueue");
dataBaseManager.insertQueue(queue);
List<MSGQueue> queueList = dataBaseManager.selectAllQueues();
Assertions.assertEquals(1, queueList.size());
// 进行删除
dataBaseManager.deleteQueue("testQueue");
queueList = dataBaseManager.selectAllQueues();
Assertions.assertEquals(0, queueList.size());
System.out.println("testDeleteQueue测试成功");
}
private Binding createTestBinding(String exchangeName, String queueName) {
Binding binding = new Binding();
binding.setExchangeName(exchangeName);
binding.setMsgQueueName(queueName);
binding.setBindingKey("testBindingKey");
return binding;
}
@Test
public void testInsertBinding() {
Binding binding = createTestBinding("testExchange", "testQueue");
dataBaseManager.insertBinding(binding);
List<Binding> bindingList = dataBaseManager.selectAllBindings();
Assertions.assertEquals(1, bindingList.size());
Assertions.assertEquals("testExchange", bindingList.get(0).getExchangeName());
Assertions.assertEquals("testQueue", bindingList.get(0).getMsgQueueName());
Assertions.assertEquals("testBindingKey", bindingList.get(0).getBindingKey());
System.out.println("testInsertBinding测试成功");
}
@Test
public void testDeleteBinding() {
Binding binding = createTestBinding("testExchange", "testQueue");
dataBaseManager.insertBinding(binding);
List<Binding> bindingList = dataBaseManager.selectAllBindings();
Assertions.assertEquals(1, bindingList.size());
// 删除
Binding toDeleteBinding = createTestBinding("testExchange", "testQueue");
dataBaseManager.deleteBinding(toDeleteBinding);
bindingList = dataBaseManager.selectAllBindings();
Assertions.assertEquals(0, bindingList.size());
System.out.println("testDeleteBinding测试成功");
}
}