当前位置: 首页 > news >正文

SpringBoot 项目学习内容详解(二)

考虑数据库的使用:

本次项目采用的是相比于 MySQL更加轻量的数据库 SQLite,SQLite的是用也是非常的广泛,在一些性能不高的产品中的使用频率是非常高的,嵌入式设备,比如 Andioid系统,就是内置的 SQLite

SQLite 的轻量化体现在,一个完整的 SQLite 数据库,只有一个单独的可执行的文件不到1M,而且SQLite是一个本地的数据库,这个数据库直接操作的是本地的硬盘文件

在 Java 要中要想使用 SQLite 不用额外安装,引入相关的依赖即可,对于SQLite来说,在进行配置相关内容的时候是不需要指定用户名和密码的,它的数据是存放在本地的硬盘文件中的,和网络无关,SQLite虽然与MySQL存在不同,但是二者都是可以通过 MyBatis 这样的框架来使用的

建库(数据库文件,就是数据库),建表 => 当上述配置和依赖都准备好了之后,程序启动就会自动的建库

建表设计:核心数据库表有这几个:交换机存储,队列存储,绑定存储

针对于这几个核心类,很容易把表设计出来,但是具体是什么时机来执行上述操作? 按照以往的操作是先把数据库表直接创建好,在启动服务器,这些操作都是在部署阶段完成的,之前的操作部署一次即可,不会反复的进行操作,但是后续接触到的更多的程序可能会反复部署多次,能够简化部署的步骤,也是很关键的,在这个项目中,我们通过代码的方式来完成自动的建表操作

<?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.zcfe.mq.mqserver.mapper.MetaMapper"> <update id="createExchangeTable"> create table if not exists exchange ( name varchar(50) primary key, type int, durable boolean, autoDelete boolean, arguments varchar(1024) ); </update> <update id="createQueueTable"> create table if not exists queue ( name varchar(50) primary key, durable boolean, exclusive boolean, autoDelete boolean, arguments varchar(1024) ); </update> <update id="createBindingTable"> create table if not exists binding ( exchangeName varchar(50), queueName varchar(50), bindingKey varchar(256) ); </update> <insert id="insertExchange" parameterType="com.zcfe.mq.mqserver.core.Exchange"> insert into exchange values(#{name}, #{type}, #{durable}, #{autoDelete}, #{arguments}); </insert> <select id="selectAllExchange" resultType="com.zcfe.mq.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.zcfe.mq.mqserver.core.MSGQueue"> insert into queue values(#{name}, #{durable}, #{exclusive}, #{autoDelete}, #{arguments}); </insert> <select id="selectAllQueues" resultType="com.zcfe.mq.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.zcfe.mq.mqserver.core.Binding"> insert into binding values(#{exchangeName}, #{queueName}, #{bindingKey}); </insert> <select id="selectAllBinding" resultType="com.zcfe.mq.mqserver.core.Binding"> select * from binding; </select> <delete id="deleteBinding" parameterType="com.zcfe.mq.mqserver.core.Binding"> delete from binding where exchangeName = #{exchangeName} and queueName = #{queueName}; </delete> </mapper>

1.当前,是把每一个建表的语句,都单独列为一个 update 标签,并且对应一个 java 方法,能否改成,一个 update 标签中包含多个建表语句,同时借助一个 java 方法,完成上述多个表的创建呢?

其实在 MyBstis 中是支持这样的操作,一个标签中包含多个 sql 语句的(前提是MySQL 或者 Oracle) 对于 SQLite 无法做到上述的功能,当你一个 update 标签中,写了多个 create table 语句的时候,只有第一个语句能执行

private Map<String, Object> arguments = new HashMap<>(); public String getArguments() { //是把当前的 arguments 参数,从 Map 转成 String (json) ObjectMapper objectMapper = new ObjectMapper(); try { return objectMapper.writeValueAsString(arguments); } catch (JsonProcessingException e) { e.printStackTrace(); } //如果代码真的出现了异常, 就返回一个空的 json 字符串 return "{}"; } //这个方法,是从数据库读取数据之后,构造的 Exchange 对象,会自动的调用到 public void setArguments(String argumentsJson) { ObjectMapper objectMapper = new ObjectMapper(); //其中的第二个参数,用来描述当前 json 字符串,要转成的 java 对象是啥类型的 //如果是一个简单的类型,直接使用对应的类型的类对象即可 //如果是集合类这样的复杂类型,可以使用 TypeReference 匿名内部类对象 //来描述复杂类型的具体信息(通过泛型来描述的) try { this.arguments = objectMapper.readValue(argumentsJson, new TypeReference<HashMap<String, Object>>() {}); } catch (JsonProcessingException e) { e.printStackTrace(); } }

如何实现 arguments 这件键值对,和数据库中的字符串类型相互转化呢?

关键的要点在于 MyBaits 在完成数据库操作的时候,会自动的调用对象的 getter 和 setter 操作

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

2.比如 MyBatis 从数据库中读数据的时候,就会调用对象的 setter 方法, 把数据库中读到的结果设置到对象的属性中,比如这个过程中,让 setArguments 参数是一个 String,并且在 setArguments 内部针对字符串进行解析,解析成一个 Map 对象

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

第二个参数"HashMap<String, Object>()" 用来描述=当前 json 字符串,要转成的java对象是啥类型的,如果是一个简单类型,就可以直接使用对应的类型类对象即可,如果是一个集合类这样的复杂类型,可以使用 TypeReference 匿名内部类对象的方式,来描述复杂类型的具体信息(通过泛型参数来描述的)

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

一般谈到初始化,会用到 构造方法,但是我们此处是一个单独的普通方法

构造方法,一般是用来初始化类的属性,一般不太会涉及到太多的业务逻辑,此处的初始化,带有业务逻辑,还是单独拎出来,手动调用比较合适一些

我们期望的是,在咱们得BrokerServer启动的时候,做出一下逻辑判定:

1.如果数据库已经存在了(表啥的都有了),不做任何操作

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

//针对数据库进行初始化 public void init() { //手动获取到 MetaMapper(防止空指针异常的情况出现) metaMapper = MqApplication.context.getBean(MetaMapper.class); if (!checkDBExists()) { //数据不存在,就进行建库建表操作 //先创建一个 data 目录 File dataDir = new File("./data"); dataDir.mkdirs(); //创建表 createTable(); //插入数据 createDefaultData(); System.out.println("[DataBaseManager]数据库初始化完成"); } else { //数据库存在,啥都不用干, System.out.println("[DataBaseManager]数据库初始化完成"); }

1,啥叫存在? => 就是指 判定 meta.db 这个文件是否存在即可

针对 DataBaseManage 进行单元测试

设计测试用例的时候,要求单元测试用例和用例之间,是需要相互独立的,不会干扰的

//这个方法,来执行准备工作,每个用例执行前,都要调用这个方法 @BeforeEach public void setUp() { MqApplication.context = SpringApplication.run(MqApplication.class); dataBaseManager.init(); } //这个方法,来处理收尾工作,每个用例执行后,都要调用这个方法 @AfterEach public void tearDown() { //这里要进行的操作就是把数据库中的数据删除(也就是把数据库文件, meta.db 直接删除了就行) //注意, 这里不能直接就删除,要先关闭上述的 context 对象 //此处的 context 对象持有了 MetaMapper 的实例,而 MetaMapper 由打开了 meta.db 数据库文件 //如果 meta.db 被别人打开了,此时删除数据库文件(meta.db)是会失败的,(这是受限于window的操作系统) //另一方面,获取context会占用8080窗口,此处释放也是为了后面能够继续使用这个窗口 MqApplication.context.close(); dataBaseManager.deleteDB(); }
@Test public void testInitTable() { //由于 init 方法,已经在前面 setUp 调用过了, 直接在测试用例的代码中检查,数据库的状态即可 //直接从数据库中进行查询查看是否符合预期 //查交换机里面应该有一个数据(匿名的 Exchange), 查队列,没有数据,查绑定也没有数据 List<Exchange> exchangesList = dataBaseManager.selectAllExchange(); List<MSGQueue> queueList = dataBaseManager.selectAllQueue(); List<Binding> bindingList = dataBaseManager.selectAllBinding(); //这里通过断言来判定结果 //注意这里的两个参数的顺序,比较相等,谁在前谁在后,是没关系的 //这里 assertEquals 的形参,第一个形参是 expected(预期的),第二个形参是 actual(实际的) Assertions.assertEquals(1, exchangesList.size()); Assertions.assertEquals("", exchangesList.get(0).getName()); Assertions.assertEquals(ExchangeType.DIRECT, exchangesList.get(0).getType()); Assertions.assertEquals(0, queueList.size()); Assertions.assertEquals(0, bindingList.size()); }
public Exchange createTestExchange(String exchangeName) { Exchange exchange = new Exchange(); exchange.setName(exchangeName); exchange.setType(ExchangeType.FANOUT); exchange.setDurable(true); exchange.setAutoDelete(false); exchange.setArguments("aaa", 111); exchange.setArguments("bbb", 222); return exchange; } @Test public void testInsertExchange(){ //构造一个 Exchange 对象,插入到数据库中,在查询出来,看是否符合预期 Exchange exchange = createTestExchange("testExchange"); dataBaseManager.insertExchange(exchange); //插入完毕,查询结果 List<Exchange> exchangeList = dataBaseManager.selectAllExchange(); 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()); Assertions.assertEquals(false, newExchange.isAutoDelete()); Assertions.assertEquals(111, newExchange.getArguments("aaa")); Assertions.assertEquals(222, newExchange.getArguments("bbb")); } @Test public void testDeleteExchange() { //先创建一个交换机,插入数据,然后在按照名字删除即可 Exchange exchange = createTestExchange("testExchange"); dataBaseManager.insertExchange(exchange); List<Exchange> exchangeList = dataBaseManager.selectAllExchange(); Assertions.assertEquals(2, exchangeList.size()); Assertions.assertEquals("testExchange", exchangeList.get(1).getName()); //进行删除操作 dataBaseManager.deleteExchange("testExchange"); Assertions.assertEquals(1, dataBaseManager.selectAllExchange().size()); //只剩下一个默认交换机 Assertions.assertEquals("", exchangeList.get(0).getName()); }
public MSGQueue createTestQueue(String queueName) { MSGQueue queue = new MSGQueue(); queue.setName(queueName); queue.setDurable(true); queue.setAutoDelete(false); queue.setExclusive(false); queue.setArguments("aaa", 111); queue.setArguments("bbb", 222); return queue; } @Test public void testInsertQueue() { MSGQueue queue = createTestQueue("testQueue"); dataBaseManager.insertQueue(queue); List<MSGQueue> queueList = dataBaseManager.selectAllQueue(); Assertions.assertEquals(1, queueList.size()); Assertions.assertEquals("testQueue", queueList.get(0).getName()); Assertions.assertEquals(true, queueList.get(0).isDurable()); Assertions.assertEquals(false, queueList.get(0).isExclusive()); Assertions.assertEquals(false, queueList.get(0).isAutoDelete()); Assertions.assertEquals(111, queueList.get(0).getArguments("aaa")); Assertions.assertEquals(222, queueList.get(0).getArguments("bbb")); } @Test public void testDeleteQueue() { MSGQueue queue = createTestQueue("testQueue"); dataBaseManager.insertQueue(queue); List<MSGQueue> queueList = dataBaseManager.selectAllQueue(); Assertions.assertEquals(1, queueList.size()); Assertions.assertEquals("testQueue", queueList.get(0).getName()); //进行删除操作 dataBaseManager.deleteQueue("testQueue"); Assertions.assertEquals(0, dataBaseManager.selectAllQueue().size()); }
public Binding createTestBinding(String exchangeName, String queueName) { Binding binding = new Binding(); binding.setExchangeName(exchangeName); binding.setQueueName(queueName); binding.setBindingKey("testBindingKey"); return binding; } @Test public void testInsertBinding() { Binding binding = createTestBinding("testExchange", "testQueue"); dataBaseManager.insertBinding(binding); List<Binding> bindingList = dataBaseManager.selectAllBinding(); Assertions.assertEquals(1, bindingList.size()); Assertions.assertEquals("testExchange", bindingList.get(0).getExchangeName()); Assertions.assertEquals("testQueue", bindingList.get(0).getQueueName()); Assertions.assertEquals("testBindingKey", bindingList.get(0).getBindingKey()); } @Test public void testDeleteBinding() { Binding binding = createTestBinding("testExchange", "testQueue"); dataBaseManager.insertBinding(binding); List<Binding> bindingList = dataBaseManager.selectAllBinding(); Assertions.assertEquals(1, bindingList.size()); Assertions.assertEquals("testExchange", bindingList.get(0).getExchangeName()); Assertions.assertEquals("testQueue", bindingList.get(0).getQueueName()); Assertions.assertEquals("testBindingKey", bindingList.get(0).getBindingKey()); //进行删除操作 dataBaseManager.deleteBinding(binding); Assertions.assertEquals(0, dataBaseManager.selectAllBinding().size()); }
http://www.jsqmd.com/news/310195/

相关文章:

  • 深度测评自考必看!10个AI论文网站TOP10榜单
  • 计算机小程序毕设实战-基于springboot+Android的计算机精品课程学习系统基于微信小程序/安卓APP的计算机课程学习系统设计与实现【完整源码+LW+部署说明+演示视频,全bao一条龙等】
  • 小程序毕设项目:基于springboot+Android的计算机精品课程学习系统(源码+文档,讲解、调试运行,定制等)
  • 【课程设计/毕业设计】基于Android的计算机精品课程学习系统基于springboot+Android的计算机精品课程学习系统【附源码、数据库、万字文档】
  • 【毕业设计】基于springboot+Android的计算机精品课程学习系统(源码+文档+远程调试,全bao定制等)
  • 《惊爆内幕!AI应用架构师如何提升企业AI成本收益》
  • paimon 主键表 vs 非主键表配置速查
  • 【无标题】知识图谱在装备领域应用场景
  • 【计算机毕业设计案例】基于springboot的小区公共收益管理系统(程序+文档+讲解+定制)
  • B2B软件选型平台深度测评:如何借力专业工具,告别选型迷航?
  • 基于YOLOv26的工业连接器缺陷智能检测系统
  • 小程序毕设选题推荐:springboot基于Android的计算机精品课程学习系基于springboot+Android的计算机精品课程学习系统【附源码、mysql、文档、调试+代码讲解+全bao等】
  • WPF Prism学习三,Commanding命令学习
  • 宏基因组分箱分析的系统介绍及其学术价值
  • Java毕设项目推荐-springboot校园社交平台基于springboot的大学生生活服务社交平台系统设计与实现基于springboot的大学生社交平台【附源码+文档,调试定制服务】
  • 使用kopia对sm18进行自动备份 - LI,Yi
  • Java毕设项目推荐-基于springboot的小区业主物业公共收益管理系统广告收益 停车位收益 租赁收益【附源码+文档,调试定制服务】
  • 【计算机毕业设计案例】基于springboot的大学生社交平台springboot校园社交平台基于springboot的大学生生活服务社交平台系统设计与实现(程序+文档+讲解+定制)
  • 如何隐藏上传人信息?看这里!
  • 内嵌式模组如何重塑物流效率链
  • 基于光流场的 Demons 算法
  • 什么是短链?如何创建短链接
  • 2026 年 5 款最适合 3D 艺术家的渲染软件推荐(附云渲染加速方案
  • 2025年可观测性平台选型指南
  • Maya 角色绑定效率提升:免费 Mansur-Rig 模块化绑定工具详解 + 云渲染方案推荐
  • 3D动画、VFX 与 CGI 有什么区别?一文讲清三大核心概念与应用场景
  • 汽车制造业可观测性平台选型指南
  • Vidu Q2参考生Pro全球上线
  • DIC技术在滑坡防治格构锚固优化模型试验中的应用
  • 腾讯搜狗输入法发布20.0版本,宣布全面AI化接入混元