项目实战 — 消息队列(3){数据库操作}

目录

一、SQLite

🍅 1、添加依赖

🍅 2、修改配置文件后缀(properties -> yaml)

 🍅 3、编写配置文件

二、建立数据表

三、添加插入和删除方法

 四、整合数据库操作(DataBaseManger类)

🍅 1、初始化方法init()

🍅 2、编写代码

 五、对数据库操作进行单元测试

 🍅 1、“准备工作”和“收尾工作”

🍅 2、编写测试类进行用力测试

🎈测试init()方法

🎈测试 交换机(插入和删除)

 * Delete 

🎈  测试DataBaseManager的队列(插入和删除)

🎈测试Binding

六、小结

🍅 1、运行时可能会报错

🍅 2、已经完成的任务


一、SQLite

MySQL数据库本身是比较重量的,所以这里使用SQLite,SQLite是更轻量的数据库

SQLite的优点:

  • 服务器性能和内存要求低
  • 减少了能源消耗
  • 自成一体,便于携带
  • 默认包含在所有的PHP安装中

它是一个本地的数据库, 操作该数据库就相当与直接操作本地的硬盘文件。

SQLite应用是很广泛的,在一些性能不高的设备上,比如移动端和嵌入式设备,就可以使用SQLite。

而且,也可以通过mybatis来使用。这里创建一个mapper文件夹将有关mybatis的xml文件放到其中。

🍅 1、添加依赖

使用过SQLite不用额外安装,直接引入依赖即可。

<!-- https://mvnrepository.com/artifact/org.xerial/sqlite-jdbc -->
<dependency><groupId>org.xerial</groupId><artifactId>sqlite-jdbc</artifactId><version>3.41.0.0</version>
</dependency>

引入以后,reload。

🍅 2、修改配置文件后缀(properties -> yaml)

这里的配置文件主要使用yaml格式。

 

 🍅 3、编写配置文件

对于SQLite文件来说,不需要指定用户名和密码,原因如下:

        首先,MySQL是一个客户端服务器结构的程序,一个数据库服务器,就会对应有很多个客户端来访问;

        但是,SQLite不同,它不是一个客户端服务器结构的程序,只有自己一个人能够访问,把数据放在本地文件上面,只有当前主机才能访问,和网络无关。

spring:datasource:
#    SQLite数据库是将数据存储在当前硬盘的某个指定的为文件中
#    这是一个相对路径,运行以后,这个文件就会出现在当前项目的目录中url: jdbc:sqlite:./data/meta.db
#    SQLite并不需要指定用户名和密码username:password:driver-class-name: org.sqlite.JDBCmybatis:mapper-location: classpath:mapper/**Mapper

二、建立数据表

SQLite没有建数据库的这概念,一个.db文件就相当于一个库,程序一启动就会自动建库。

主要建立以下几个表:

        * 交换机存储

        * 队列存储

        * 绑定存储

这里通过代码自动完成建表操作,使用Mybatis执行SQL语句。

MyBatis基本使用流程回顾:

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

        (2)创建对应的xml,通过xml实现interface中的抽象方法 

 创建一个mapper包,放置interface。

 

 在MeteMapper接口中建立三个核心的建表方法:

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

然后再Mapper文件夹中建立对应的xml文件,

编写myBatis文件,关于myBatis框架的使用,如果不了解,可以参考博客https://blog.csdn.net/qq_52136076/category_12392841.html?spm=1001.2014.3001.5482

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.tigermq.mqserver.mapper.MetaMapper"><update id="createExchangeTable">create table if not exists exchange(name varchar(50) primary key,type int,durable boolean,)</update><update id="createQueueTable">create table if not exists queue(name varchar(50) primary key,durable boolean,exclusive boolean,)</update><update id="createBindingTable">create table if not exists binding(exchangeName varchar(50),queueName varchar(50),bindingKey varchar(256))</update></mapper>

三、添加插入和删除方法

 在MentaMapper接口中添加插入和删出方法,其中

  对于交换机和队列这两个表,由于使用name作为主键,所以直接按照name进行删除即可。

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

//    针对三个表,进行插入\删除\查找操作@Insert("insert into exchange values(#{name},#{type},#{durable})")void insertExchange(Exchange exchange);@Select("select * from exchange")List<Exchange> selectAllExchanges();@Delete("delete from exchange where name = #{exchangeName}")void deleteExchange(String exchangeName);@Insert("insert into queue values (#{name},#{durable},#{exclusive})")void insertQueue(MSGQueue queue);@Select("select * from queue")List<MSGQueue> selectAllQueues();@Delete("delete from queue where name = (#{queueName})")void deleteQueue(String queueName);@Insert("insert into binding values(#{exchangeName},#{queueName},#{bindingKey})")void insertBinding(Binding binding);@Select("select * from binding")List<Binding> selectAllBindings();@Delete("delete from binding where exchangeName = #{exchangeName} and queueName = #{queueName}")void deleteBinding(Binding binding);

 四、整合数据库操作(DataBaseManger类)

创建一个包datacenter .都是针对数据进行操作

 在包中创建一个DataBaseManger类

🍅 1、初始化方法init()

首先,由于构造方法初始化一般都不会带有很多逻辑(也可以用,但是一般习惯不适用构造方法),而这里初始化数据库需要很多业务逻辑,所以就自定义了一个init()方法。

数据库的初始化其实就是 建库建表 + 插入一些默认数据 

基本逻辑:

        如果数据已经存在了,就不做出任何操作

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

如何判断数据库是否存在?

        答:判断meta.db文件是否存在。

🍅 2、编写代码

根据前面的逻辑,编写如下代码:


/*
* 通过这个类,整合之前的数据库操作
* */
public class DataBaseManger {
//    从spring中拿到现成的对象private MetaMapper metaMapper;//    针对数据库进行初始化
//    因为这里的的初始化需要带有业务逻辑,所以就不适用构造方法,因为构造方法一般不会涉及到很多的业务逻辑public void init(){
//          手动的获取到MetaMappermetaMapper = TigerMqApplication.context.getBean(MetaMapper.class);if(!checkDBExists()){//            创建一个data目录File dataDir = new File("/data");dataDir.mkdirs();
//            数据库不存在,就进行建库建表操作createTable();
//            创建默认数据createDafaultData();System.out.println("[DataBaseManger]数据库初始化完成");}else{
//            数据库存在了System.out.println("[DataBaseManger]数据库已经存在");}}public void deleteDB(){File file = new File("./data/meta.db");boolean ret = file.delete();if (ret){System.out.println("[DataBaseManager]DB文件已经删除成功");}else{System.out.println("[DataBaseManager]DB文件删除失败");}//这个Delete只能删除空目录,所以删除的时候要保证目录是空的File dataDir = new File("./data");ret = dataDir.delete();if(ret){System.out.println("[DataBaseManger] 删除数据库目录成功");}else {System.out.println("[DataBaseManger] 删除数据库目录失败");}}//    判断文件是否存在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("[DataBaseManger]创建表完成");}//    创建默认数据
//    此处主要是添加一个默认的交换机:DIRECTprivate void createDafaultData() {
//        构造一个默认的交换机Exchange exchange = new Exchange();exchange.setName("");exchange.setType(ExchangeType.DIRECT);exchange.setDurable(true);exchange.setAutoDelete(false);metaMapper.insertExchange(exchange);System.out.println("[DataBaseManger]创建初始数据已经完成");}//    其他的一些数据库操作public void  insertExchange(Exchange exchange){metaMapper.insertExchange(exchange);}public List<Exchange> selectAllExchanges(){return metaMapper.selectAllExchanges();}public void deleteExchange(String exchangeName){metaMapper.deleteExchange(exchangeName);}public void insertQueue(MSGQueue queue){metaMapper.insertQueue(queue);}public List<MSGQueue> selectAllQueues(){return metaMapper.selectAllQueues();}public void deleteQueue(String queueName){metaMapper.deleteQueue(queueName);}public void insertBinding(Binding binding){metaMapper.insertBinding(binding);}public List<Binding> selectAllBindings(){return metaMapper.selectAllBindings();}public void deleteBinding(Binding binding){metaMapper.deleteBinding(binding);}
}

但是,上面的metaMapper还没有进行构造,为空,直接运行就会报错,但是这里不能使用@Autowired进行对象注入,因为里不打算把DataBaseManager设置为一个Bean,所以我们就,我们可以在启动类中,对对象metaMapper进行构造。

在启动类中:

@SpringBootApplication
public class TigerMqApplication {public static ConfigurableApplicationContext context;public static void main(String[] args) {context = SpringApplication.run(TigerMqApplication.class, args);}}

 在init()方法中手动获取到metaMapper对象:添加以下代码

//          手动的获取到MetaMappermetaMapper = TigerMqApplication.context.getBean(MetaMapper.class);

 五、对数据库操作进行单元测试

创建测试类DataBaseManagerTests

 🍅 1、“准备工作”和“收尾工作”

添加两个类,主要是为了放置每个测试用力之间不会收到干扰而创建的。

首先是“准备工作”setUp(),主要是为了调用init()方法,初始化数据库

然后是“收尾工作”tearDown(),主要是为了删除掉.db文件。

@BeforEach指的是每个用例执行前都会调用这个方法

@AfterEach指的是每个用力执行完后调用这个方法

编写代码:

@SpringBootTest
public class DataBaseMangerTests {private DataBaseManger dataBaseManger = new DataBaseManger();//    编写多个方法,每个方法都是一组单元测试用例
//    编写两个方法,分别用于进行“准备工作”和收尾工作
//    这是为了让每个测试用力之间不会收到干扰而创建的//使用该方法,进行准备工作,每个用力执行前都要调用这个方法@BeforeEachpublic void setUp(){
//        由于init中,需要经过context对象拿到metaMapper示例
//        所以需要先把context对象构造出来TigerMqApplication.context = SpringApplication.run(TigerMqApplication.class);dataBaseManger.init();}//    该方法用来执行收尾工作,每个用例执行后,需要调用这个方法@AfterEachpublic void tearDown(){
//        及那个数据库清空,删掉.db文件
//        删除之前需要关闭context对象。
//        原因是因为context持有了MetaMapper类的实力对象,
//        而该对象打开了meta.db文件,而在打开的情况下,删除操作是不能进行的TigerMqApplication.context.close();dataBaseManger.deleteDB();}
}

🍅 2、编写测试类进行用力测试


        🎈测试init()方法

 @Testpublic void  testInitTable(){
//        由于init()方法已经被调用过了,直接在测试用力代码中检查当前数据库状态
//        从数据库中查询数据是否符合预期
//        查交换机表,会有一个匿名exchange数据List<Exchange> exchangeList = dataBaseManger.selectAllExchanges();List<MSGQueue> queueList = dataBaseManger.selectAllQueues();List<Binding> bindingList = dataBaseManger.selectAllBindings();//       使用断言
//       判断1和exchangeList是否相等
//       assertEquals(预期值,实际值)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());}

       


🎈测试 交换机(插入和删除)

* Insert

private Exchange createTestExchange(String exchangeName){Exchange exchange = new Exchange();exchange.setName(exchangeName);exchange.setType(ExchangeType.FANOUT);exchange.setDurable(true);return exchange;}@Testpublic void testInsertExchange(){
//        构造一个Exchange对象,插入到数据库中,再查询出来,看是否符合预期Exchange exchange = createTestExchange("testExchange");dataBaseManger.insertExchange(exchange);List<Exchange> exchangeList = dataBaseManger.selectAllExchanges();Assertions.assertEquals(2,exchangeList.size());Exchange newExchange = exchangeList.get(1);Assertions.assertEquals("testExchange",newExchange.getName());Assertions.assertEquals(ExchangeType.FANOUT,newExchange.getType());Assertions.assertEquals(true,newExchange.isDurable());}

 

 * Delete 

@Testpublic void testDeleteExchange(){
//        先构造一个交换机Exchange exchange = createTestExchange("testExchange");dataBaseManger.insertExchange(exchange);List<Exchange> exchangeList = dataBaseManger.selectAllExchanges();Assertions.assertEquals(2,exchangeList.size());Assertions.assertEquals("testExchange",exchangeList.get(1).getName());//        进行删除操作dataBaseManger.deleteExchange("testExchange");
//        再次查询exchangeList = dataBaseManger.selectAllExchanges();Assertions.assertEquals(1,exchangeList.size());Assertions.assertEquals("",exchangeList.get(0).getName());}


🎈  测试DataBaseManager的队列(插入和删除)

* Insert

private MSGQueue createTestQueue(String queueName){MSGQueue queue = new MSGQueue();queue.setName(queueName);queue.setDurable(true);queue.setExclusive(false);return queue;}@Testpublic void testInsertQueue(){MSGQueue queue = createTestQueue("testQueue");dataBaseManger.insertQueue(queue);List<MSGQueue> queueList = dataBaseManger.selectAllQueues();Assertions.assertEquals(1,queueList.size());MSGQueue newQueue = queueList.get(0);Assertions.assertEquals("testQueue",newQueue.getName());}

* Delete 

 @Testpublic void testDeleteQueue(){MSGQueue queue = createTestQueue("testQueue");dataBaseManger.insertQueue(queue);List<MSGQueue> queueList = dataBaseManger.selectAllQueues();Assertions.assertEquals(1,queueList.size());//        删除dataBaseManger.deleteQueue("testQueue");queueList = dataBaseManger.selectAllQueues();Assertions.assertEquals(0,queueList.size());}

 

         


🎈测试Binding

* Insert

public Binding createTestBinding(String exchangeName,String queueName){Binding binding = new Binding();binding.setExchangeName(exchangeName);binding.setQueueName(queueName);binding.setBindingKey("testBindingKey");return binding;}@Testpublic void testInsertBinding(){Binding binding = createTestBinding("testExchange","tesQueue");dataBaseManger.insertBinding(binding);List<Binding> bindingList = dataBaseManger.selectAllBindings();Assertions.assertEquals(1,bindingList.size());Assertions.assertEquals("testExchange",bindingList.get(0).getExchangeName());Assertions.assertEquals("tesQueue",bindingList.get(0).getQueueName());Assertions.assertEquals("testBindingKey",bindingList.get(0).getBindingKey());}

*Delete 

   @Testpublic void testDeleteBinding(){Binding binding = createTestBinding("testExchange","testQueue");dataBaseManger.insertBinding(binding);List<Binding> bindingList = dataBaseManger.selectAllBindings();Assertions.assertEquals(1,bindingList.size());//        删除操作Binding toDeleteBinding = createTestBinding("testExchange","testQueue");dataBaseManger.deleteBinding(toDeleteBinding);bindingList = dataBaseManger.selectAllBindings();Assertions.assertEquals(0,bindingList.size());}


六、小结

🍅 1、运行时可能会报错

在刚开始测试运行的过程中,代码可能会报错。我在运行的时候就遇到了以下的错误,你们可能也会遇见

解决方案我是上网查到的:

Error creating bean with name ‘dataSource‘ defined in class path resource解决办法_张道长的博客-CSDN博客

🍅 2、已经完成的任务

(1)项目需求分析:项目实战 — 消息队列(1) {需求分析}_‍️藿香正气水的博客-CSDN博客

(2)设计核心类: 项目实战 — 消息队列(2){创建核心类}_‍️藿香正气水的博客-CSDN博客

(3)设计数据库,并且针对数据库代码进行了单元测试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/53294.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

封装动态SQL的插件

最近根据公司的业务需要封装了一个简单的动态SQL的插件&#xff0c;要求是允许用户在页面添加SQL的where条件&#xff0c;然后开发者只需要给某个接口写查询对应的表&#xff0c;参数全部由插件进行拼接完成。下面是最终实现&#xff1a; 开发人员只需要在接口写上下面的查询SQ…

RISC-V基础之浮点指令(包含实例)

RISC-V体系结构定义了可选的浮点扩展&#xff0c;分别称为RVF、RVD和RVQ&#xff0c;用于操作单精度、双精度和四倍精度的浮点数。RVF/D/Q定义了32个浮点寄存器&#xff0c;f0到f31&#xff0c;它们的宽度分别为32位、64位或128位。当一个处理器实现了多个浮点扩展时&#xff0…

边写代码边学习之RNN

1. 什么是 RNN 循环神经网络&#xff08;Recurrent Neural Network&#xff0c;RNN&#xff09;是一种以序列数据为输入来进行建模的深度学习模型&#xff0c;它是 NLP 中最常用的模型。其结构如下图&#xff1a; x是输入&#xff0c;h是隐层单元&#xff0c;o为输出&#xff…

Spring Cloud Eureka 和 zookeeper 的区别

CAP理论 在了解eureka和zookeeper区别之前&#xff0c;我们先来了解一下这个知识&#xff0c;cap理论。 1998年的加州大学的计算机科学家 Eric Brewer 提出&#xff0c;分布式有三个指标。Consistency&#xff0c;Availability&#xff0c;Partition tolerance。简称即为CAP。…

Istio 安全 mTLS认证 PeerAuthentication

这里定义了访问www.ck8s.com可以使用http也可以使用https访问&#xff0c;两种方式都可以访问。 那么是否可以强制使用mtls方式去访问&#xff1f; mTLS认证 PeerAuthentication PeerAuthentication的主要作用是别人在和网格里的pod进行通信的时候&#xff0c;是否要求mTLS mTL…

完全背包问题

题目链接 题意&#xff1a;在01背包的基础上多了每个物品都可以无限取的条件 思路&#xff1a;首先考虑在01背包的基础上的暴力枚举&#xff0c;我们可以在枚举前i件物品最多拿j的容量时再遍历当前物品拿的数量 贴一个暴力tle代码&#xff1a; #include<bits/stdc.h> #d…

分布式电网动态电压恢复器模拟装置电子设计大赛

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;85电网 获取完整论文报告结构框图工程源文件 摘要&#xff1a;本装置采用DC-AC及AC-DC-AC双重结构&#xff0c;前级采用功率因数校正&#xff08;PFC&#xff09;电路完成AC-DC变换&#xff0c;改善输入端电网电能质量。后…

靶形数独

题目描述 小城和小华都是热爱数学的好学生&#xff0c;最近&#xff0c;他们不约而同地迷上了数独游戏&#xff0c;好胜的他们想用数独来一比高低。但普通的数独对他们来说都过于简单了&#xff0c;于是他们向 Z 博士请教&#xff0c;Z 博士拿出了他最近发明的“靶形数独”&am…

YOLOv5入门

模型检测 关键参数 weights:训练好的模型文件 source: 检测的目标&#xff0c;可以是单张图片、文件夹、屏幕或者摄像头等 conf-thres: 置信度闯值&#xff0c;越低框越多&#xff0c;越高框越少 iou-thres: IOU闻值&#xff0c;越低框越少&#xff0c;越少框越多 torch.hu…

opencv-32 图像平滑处理-高斯滤波cv2.GaussianBlur()

在进行均值滤波和方框滤波时&#xff0c;其邻域内每个像素的权重是相等的。在高斯滤波中&#xff0c;会将中心点的权重值加大&#xff0c;远离中心点的权重值减小&#xff0c;在此基础上计算邻域内各个像素值不同权重 的和。 基本原理 在高斯滤波中&#xff0c;卷积核中的值不…

阶段总结(linux基础)

目录 一、初始linux系统 二、基本操作命令 三、目录结构 四、文件及目录管理命令 查看文件内容 创建文件 五、用户与组管理 六、文件权限与压缩管理 七、磁盘管理 八、系统程序与进程管理 管理机制 文件系统损坏 grub引导故障 磁盘资源耗尽 程序与进程的区别 查…

layui之layer弹出层的icon数字及效果展示

layer的icon样式 icon如果在信息提示弹出层值(type为0)可以传入0-6&#xff0c;icon与图标对应关系如下&#xff1a; 如果是加载层&#xff08;type为3&#xff09;可以传入0-2&#xff0c;icon与图标对应关系如下&#xff1a;