从零手搓一个【消息队列】创建核心类, 数据库设计与实现
文章目录
- 一、创建核心类
- 1, 交换机
- 2, 交换机类型
- 3, 队列
- 4, 绑定
- 5, 交换机转发 & 绑定规则
- 6, 消息
- 7, 消息属性
- 二、数据库设计
- 1, 使用 SQLite
- 2, 使用 MyBatis
- 2.1, 创建 Interface
- 2.2, 创建 xml 文件
- 三、硬盘管理 -- 数据库
- 1, 创建 DataBaseManager 类
- 2, init() 初始化数据库
- 3, insertDefaultData() 插入默认数据
- 4, createTable() 创建数据表
- 5, isDBExists() 数据库是否存在
- 6, deleteTables() 删除数据表
- 7, 封装数据库的增删查操作
- 四、小结
创建 Spring Boot 项目, Spring Boot 2 系列版本, Java 8 , 引入 MyBatis, Lombok 依赖
提示:是正在努力进步的小菜鸟一只,如有大佬发现文章欠佳之处欢迎批评指点~ 废话不多说,直接上干货!
整体目录结构 :
本文主要实现 server 包
一、创建核心类
上篇文章 分析了项目需求, 介绍了项目中重要的核心概念和核心 API, 以及重要板块
一个消息队列中需要的交换机, 队列, 绑定, 消息等核心概念, 以面向对象的思想, 在server.core 包下创建出来对应的类
1, 交换机
@Data
public class Exchange {// 身份标识(唯一, RabbitMQ 就是以 name 作为身份标识的)private String name;// 三种交换机类型private ExchangeTypeEnum type = ExchangeTypeEnum.DIRECT;// 是否需要持久化存储private boolean durable = false;// 是否(交换机没人使用时)自动删除 ------------------>先不实现private boolean autoDelete = false;// 创建交换机时, 指定的参数选项 ------------------>先不实现// 数据库中存储 String 类型, 需要序列化private Map<String, Object> arguments = new HashMap<>();/*** 实现序列化, 修改 getter()和 setter(), 供数据库使用*/public String getArguments(){ObjectMapper objectMapper = new ObjectMapper();// 序列化 往数据库里写try {return objectMapper.writeValueAsString(arguments);} catch (JsonProcessingException e) {e.printStackTrace();}return "{}";}public void setArguments(String arguments) {ObjectMapper objectMapper = new ObjectMapper();// 反序列化 从数据库里读try {this.arguments = objectMapper.readValue(arguments, new TypeReference<HashMap<String, Object>>() {});} catch (JsonProcessingException e) {e.printStackTrace();}}/*** 便于 测试/ 代码内部调用 时使用*/public Object getArguments(String key) {return arguments.get(key);}public void setArguments(String key, Object value) {arguments.put(key, value);}public void setArguments(Map<String, Object> arguments) {this.arguments = arguments;}
}
本项目未实现 autoDelete 和 arguments
2, 交换机类型
这是一个枚举类, 包含直接交换机, 扇出交换机, 主题交换机
public enum ExchangeTypeEnum {DIRECT(0),FANOUT(1),TOPIC(2);private final int type;ExchangeTypeEnum(int type) {this.type = type;}public int getType() {return type;}
}
3, 队列
类名不设为 Queue, 防止和标准库中的 Queue 冲突
@Data
public class MessageQueue {// 唯一标识private String name;// 是否需要持久化存储private boolean durable = false;// 是否为独有(如果是独有, 只能被一个消费者使用) ------------------>先不实现private boolean exclusive = false;// 是否(队列没人使用时)自动删除 ------------------>先不实现private boolean autoDelete = false;// 创建队列时, 指定的参数选项 ------------------>先不实现// 数据库中存储 String 类型, 需要序列化private Map<String, Object> arguments = new HashMap<>();/*** 实现序列化, 修改 getter()和 setter(), 供数据库使用*/public String getArguments(){ObjectMapper objectMapper = new ObjectMapper();// 序列化 往数据库里写try {return objectMapper.writeValueAsString(arguments);} catch (JsonProcessingException e) {e.printStackTrace();}return "{}";}public void setArguments(String arguments) {ObjectMapper objectMapper = new ObjectMapper();// 反序列化 从数据库里读try {this.arguments = objectMapper.readValue(arguments, new TypeReference<HashMap<String, Object>>() {});} catch (JsonProcessingException e) {e.printStackTrace();}}/*** 便于 测试/ 代码内部调用 时使用*/public Object getArguments(String key) {return arguments.get(key);}public void setArguments(String key, Object value) {arguments.put(key, value);}public void setArguments(Map<String, Object> arguments) {this.arguments = arguments;}
}
暂不实现 exclusive, autoDelete, arguments
4, 绑定
@Data
public class Binding {// 绑定的消息队列标识private String queueName;// 绑定的交换机标识private String exchangeName;// 绑定的 keyprivate String bindingKey;
}
bindingKey 是在创建交换机和队列的绑定时指定的, 生产者发布消息时, 需额外指定一个 routingKey
如果是直接交换机, routingKey 作为队列的唯一标识
如果是扇出交换机, routingKey 为 null, 无需使用
如果是主题交换机, routingKey 需和 bindingKey 匹配
5, 交换机转发 & 绑定规则
在此先不展示, 在后续文章中对应的部分再展示 防止思路混淆
6, 消息
@Data
public class Message implements Serializable {// 属性private BasicProperties basicProperties = new BasicProperties();// 正文private byte[] body;// 消息存储在文件中的偏移量(字节, 约定 "[,)" 区间 )private transient long offsetBegin = 0;private transient long offsetEnd = 0;// 是否合法(逻辑删除的标记, 0x1 有效, 0x0 无效)private byte isValid = 0x1;// 提供工厂方法, 封装 Message 类的创建过程public static Message createMessage(String routingKey, BasicProperties basicProperties, byte[] body) {Message message = new Message();if (basicProperties != null) {message.setBasicProperties(basicProperties);}message.setMessageId("M$" + UUID.randomUUID().toString().replace("-", ""));message.setRoutingKey(routingKey);message.setBody(body);return message;}// 下面这些方法是为了封装 basicProperties 中的 getter()和 setter()public String getMessageId() {return basicProperties.getMessageId();}public void setMessageId(String id) {basicProperties.setMessageId(id);}public String getRoutingKey() {return basicProperties.getRoutingKey();}public void setRoutingKey(String key) {basicProperties.setRoutingKey(key);}public int getDeliverMode() {return basicProperties.getDeliverMode();}public void setDeliverMode(int value) {basicProperties.setDeliverMode(value);}
}
- Message 需要实现
Serializable 接⼝
. 后续需要把 Message 写⼊⽂件以及进⾏⽹络传输. - basicProperties 是消息的属性信息. body 是消息体.
- offsetBeg 和 offsetEnd 表⽰消息在消息⽂件中所在的起始位置和结束位置. 这⼀块具体的设计后⾯再详细介绍. 使⽤
transient 关键字
避免属性被序列化. - isValid ⽤来表⽰消息在⽂件中是否有效. 这⼀块具体的设计后⾯再详细介绍.
- createMessage() 相当于⼀个⼯⼚⽅法, ⽤来创建⼀个 Message 实例. messageId 通过UUID 的⽅式⽣成.
文件中的数据不相当于一个顺序表, 如果要真正删除一条消息, 是不是需要把后面的数据整体往前挪动? 这无疑是个低效操作, 因此, 对于 “删除消息” 这种高频操作, 逻辑删除显然是更优解, 但也不能让消息无限制的堆在文件中, 所以后面会参考 JVM 的 GC , 自主实现清理文件的功能
7, 消息属性
这个类作为Message 类的 引用类型的成员属性, 也需要实现 Serializable 接⼝
, 否则 message 对象不能被序列化
@Data
public class BasicProperties implements Serializable {// 消息的唯一标识(UUID)private String messageId;// 和 bindingKey 匹配(如果交换机为 DIRECT, 该值就是队列名, 如果交换机为 FANOUT, 该值为 null )private String routingKey;// 是否要消息持久化( RabbitMQ 就是使用 1 表示不持久化, 2 表示持久化)private int deliverMode = 2;// ... 其他属性暂不考虑
}
二、数据库设计
1, 使用 SQLite
对于 Exchange, MSGQueue, Binding, 我们使⽤数据库进⾏持久化保存.
此处我们使⽤的数据库是 SQLite, 是⼀个更轻量的数据库
SQLite 只是⼀个动态库(当然, 官⽅也提供了可执⾏程序 exe), 我们在 Java 中直接引⼊ SQLite 依赖, 即可直接使⽤, 不必安装其他的软件.
MySQL 是一个客户端服务器结构的程序, SQLite 相当于直接操作本地的硬盘文件
在pom.xml
文件中的 “dependencies” 标签中拷贝 :
<dependency><groupId>org.xerial</groupId><artifactId>sqlite-jdbc</artifactId><version>3.41.0.1</version></dependency>
- 在 resource 目录下创建 application.yml 文件配置SQLite数据源, 拷贝:
spring:datasource:url: jdbc:sqlite:./data/meta.db # 注意这个路径username:# 不需要password:# 不需要driver-class-name: org.sqlite.JDBCmybatis:mapper-locations: classpath:mapper/**Mapper.xml
数据库文件的位置就是
./data/meta.db
, 数据库的数据就在这里
2, 使用 MyBatis
实现 mapper 包
2.1, 创建 Interface
在 server.mapper 包下定义一个 MetaMapper 接口
, 需要提供 交换机, 队列, 绑定 的建表, 插入, 删除 , 查询的 API (抽象方法)
不需要使用sql 语句建库, 创建出
./data/meta.db
这个文件就相当于建库了, 后面再写创建文件的操作
@Mapper
public interface MetaMapper {/*** 建表*/void createExchangeTable();void createQueueTable();void createBindingTable();/*** exchange 表*/void insertExchange(Exchange exchange);void deleteExchange(String exchangeName);List<Exchange> selectAllExchanges();/*** queue 表*/void insertQueue(MessageQueue queue);void deleteQueue(String queueName);List<MessageQueue> selectAllQueues();/*** binding 表*/void insertBinding(Binding binding);void deleteBinding(Binding binding);List<Binding> selectAllBindings();
}
2.2, 创建 xml 文件
在 resource 目录下, 新建一个 mapper 包, 创建 MetaMapper.xml 文件, 在这个文件中编写 sql 语句, 实现上述在 MetaMapper 接口中的抽象方法
在 xml 文件中拷贝:
<?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.demo.server.mapper.MetaMapper"></mapper>
其中 namespace 这个字段的值要对应刚才定义的
MetaMapper 接口
的路径
- 建表(使用 update 标签即可)
<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>
- exchange 表的增删查的 sql
<insert id="insertExchange" parameterType="com.example.demo.server.core.Exchange">insert into exchange values(#{name}, #{type}, #{durable}, #{autoDelete}, #{arguments});</insert><select id="selectAllExchanges" resultType="com.example.demo.server.core.Exchange">select * from exchange;</select><delete id="deleteExchange" parameterType="java.lang.String">delete from exchange where name = #{exchangeName};</delete>
- queue 表的增删查的 sql
<insert id="insertQueue" parameterType="com.example.demo.server.core.MessageQueue">insert into queue values(#{name}, #{durable}, #{exclusive}, #{autoDelete}, #{arguments});</insert><select id="selectAllQueues" resultType="com.example.demo.server.core.MessageQueue">select * from queue;</select><delete id="deleteQueue" parameterType="java.lang.String">delete from queue where name = #{queueName};</delete>
- queue 表的增删查的 sql
<insert id="insertBinding" parameterType="com.example.demo.server.core.Binding">insert into binding values(#{exchangeName}, #{queueName}, #{bindingKey});</insert><select id="selectAllBindings" resultType="com.example.demo.server.core.Binding">select * from binding;</select><delete id="deleteBinding" parameterType="com.example.demo.server.core.Binding">delete from binding where exchangeName = #{exchangeName} and queueName = #{queueName};</delete>
三、硬盘管理 – 数据库
实现 datacenter 包中的 DataBaseManager 类
datacenter 这个包中整合硬盘上的数据管理 + 内存上的数据管理
硬盘上的数据管理又整合了 数据库中的数据管理 + 文件中的数据管理
1, 创建 DataBaseManager 类
成员属性需要 MetaMapper 的对象, 用来封装刚才编写的数据库的 API
但并不使用 SpringBoot 的依赖注入 (@AutoWired), 而是使用以来查找的方式获取到 metaMapper
public class DataBaseManager {private MetaMapper metaMapper;}
在启动类中初始化容器
@SpringBootApplication
public class DemoApplication {public static ConfigurableApplicationContext context;public static void main(String[] args) throws IOException {context = SpringApplication.run(DemoApplication.class, args);}
}
2, init() 初始化数据库
对于 DataBaseManager 类的初始化工作, 不仅仅是对成员属性的初始化, 而是需要一些额外的业务逻辑, 这种情况就不使用构造方法了, 而是单独定义一个方法
初始化工作: metaMapper + 建库建表 + 插入默认数据
如果是第一次启动服务器, 没有数据库则建库建表
如果是重启服务器, 已有数据库则不做处理
MyBatis 在第一次创建数据表的时候就会创建出 ./data/meta.db
这个文件, 但前提是要有 ./data
这个目录, 所以要先手动创建
public void init() {this.metaMapper = DemoApplication.context.getBean(MetaMapper.class);if(!isDBExists()) {// 创建目录File file = new File("./data");file.mkdirs();// 创建数据表createTable();// 插入数据insertDefaultData();}}
3, insertDefaultData() 插入默认数据
创建一个默认的交换机(直接交换机)
public void insertDefaultData() {Exchange exchange = new Exchange();exchange.setName("");exchange.setType(ExchangeTypeEnum.DIRECT);exchange.setDurable(false);exchange.setAutoDelete(false);metaMapper.insertExchange(exchange);}
4, createTable() 创建数据表
public void createTable() {metaMapper.createExchangeTable();metaMapper.createQueueTable();metaMapper.createBindingTable();}
5, isDBExists() 数据库是否存在
SQLite 是一个轻量级数据库, 操作 SQLite 相当于操作本地的硬盘文件, 所以检查数据库是否存在就是检查数据库文件是否存在
public boolean isDBExists() {File file = new File("./data/meta.db");return file.exists();}
6, deleteTables() 删除数据表
同上, 删除数据库就是删除文件, 先删文件再删目录
public void deleteTables(){File file = new File("./data/meta.db");file.delete();File dir = new File("./data");dir.delete();}
7, 封装数据库的增删查操作
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(MessageQueue queue) {metaMapper.insertQueue(queue);}public List<MessageQueue> 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);}
四、小结
本文主要实现了两点 :
- 1, 根据面向对象思想, 创建出了交换机, 队列, 绑定, 消息, 等核心概念的类
- 2, 持久化存储 --> 硬盘管理 --> 数据库
-
- 2.1, 数据库设计, 使用 SQLite, 并结合 MyBatis 编写了交换机, 队列, 绑定的建表, 增, 删, 查的 sql
-
- 2.2, 使用 DataBaseManager 这个类管理数据库中的数据, 因为仅仅有sql语句不足以支撑所有的业务逻辑, 还需要对数据库的初始化, 判断存在, 删除等做进一步的封装
篇幅有限, 目前为止, 持久化存储 --> 硬盘管理 --> 文件 这个板块还没实现
下篇会实现消息在文件上的存储( 文件管理 : MessageFileManager 类)
相关文章:
从零手搓一个【消息队列】创建核心类, 数据库设计与实现
文章目录 一、创建核心类1, 交换机2, 交换机类型3, 队列4, 绑定5, 交换机转发 & 绑定规则6, 消息7, 消息属性 二、数据库设计1, 使用 SQLite2, 使用 MyBatis2.1, 创建 Interface2.2, 创建 xml 文件 三、硬盘管理 -- 数据库1, 创建 DataBaseManager 类2, init() 初始化数据库…...
14:00面试,14:06就出来了,这问的过于变态了。。。
前言 刚从小厂出来,没想到在另一家公司我又寄了。 在这家公司上班,每天都要加班,但看在钱给的比较多的份上,也就不太计较了。但万万没想到5月一纸通知,所有人不准加班了,不仅加班费没有了,薪资…...
url请求头信息
Accept Accept:请求报头域,用于指定客户端可接受哪些类型的信息。 Accept-Language Accept-Language:指定客户端可接受的语言类型。 Accept-Encoding Accept-Encoding:指定客户端可接受的内容编码。 Host Host:…...
【Oracle】Oracle系列之十六--数据库备份
文章目录 往期回顾1. 数据库备份的分类1.1 逻辑备份与物理备份(1)逻辑备份(2)物理备份(3)归档模式与非归档模式 1.2 完全备份/差异备份/增量备份 2. Oracle 逻辑备份2.1 EXP/IMP(1)E…...
uni-app:实现页面效果3
效果 代码 <template><view><!-- 风速风向检测器--><view class"content_position"><view class"content"><view class"SN"><view class"SN_title">设备1</view><view class&quo…...
计算机网络基础(一):网络系统概述、OSI七层模型、TCP/IP协议及数据传输
通信,在古代是通过书信与他人互通信息的意思。 今天,“通信”这个词的外沿已经得到了极大扩展,它目前的大意是指双方或多方借助某种媒介实现信息互通的行为。 如果按照当代汉语的方式理解“通信”,那么古代的互遣使节、飞鸽传书…...
互联网金融理财知识点简单总结
互联网金融理财知识点总结 互联网金融理财是指通过互联网平台进行资产管理和投资的一种金融方式。它结合了金融、科技和互联网,为投资者提供了更多选择和便捷性。本文将介绍互联网金融理财的关键知识点,包括理财基础、投资产品、风险管理和未来趋势等方…...
微信小程序template界面模板导入
我们有些时候 会有一些比较大但并不复杂的界面结构 这个时候 你可以试试这种导入模板的形式 我们在根目录创建一个 template 目录 然后下面创建一个 text文件夹下面创建一个 test.wxml 参考代码如下 <template name"textIndex"><text class "testw&…...
C/C++跨平台构建工具CMake-----在C++源码中读取CMakeLists.txt配置文件中的内容
文章目录 1.需求描述2.需求准备2.1 创建项目2.2 编辑CMakeLists.txt文件2.3 编写C文件2.4 编译构建项目 3.需求实现3.1 在CMakeLists.txt中输出日志信息3.2 增加配置生成C头文件3.3在C 源码中访问配置的值3.4 C文件中读取CMakeLists.txt中的字符串 总结 1.需求描述 当我们开发…...
【MVP争夺战】python实现-附ChatGPT解析
1.题目 MVP争夺战 知识点 :DFS搜索 时间限制:1s 空间限制:256MB 限定语言:不限 题目描述: 在星球争霸篮球赛对抗赛中,强大的宇宙战队,希望每个人都能拿到MVP。 MVP的条件是,单场最高分得分获得者,可以并列,所以宇宙战队决定在比赛中尽可能让更多的队员上场,且让所有有得…...
6 个最佳免费 Android 数据恢复软件
如果您是 Android 用户,您可能会发现没有回收站。然而,聪明的开发人员已经创建了各种 Android 数据恢复软件程序,可以解决各种与数据丢失相关的问题。 Android 数据恢复软件如何工作? 问题是当你删除一个文件时,它的数…...
数学建模Matlab之数据预处理方法
本文综合代码来自文章http://t.csdnimg.cn/P5zOD 异常值与缺失值处理 %% 数据修复 % 判断缺失值和异常值并修复,顺便光滑噪音,渡边笔记 clc,clear;close all; x 0:0.06:10; y sin(x)0.2*rand(size(x)); y(22:34) NaN; % 模拟缺失值 y(89:95) 50;% 模…...
如何保证Redis的HA高可用
目录 1.关于Redis2.Redis 的使用场景3.Redis的高可用3.1 哨兵模式(Sentinel)3.2 集群模式(Cluster) 4.参考 本文主要介绍Redis如何保证高可用。 1.关于Redis Redis(Remote Dictionary Server)是一个开源的…...
第一百六十三回 如何在任意位置显示PopupMenu
文章目录 概念介绍使用方法示例代码 我们在上一章回中介绍了PopupMenuButton相关的内容,本章回中将介绍如何在任意位置显示PopupMenu.闲话休提,让我们一起Talk Flutter吧。 概念介绍 我们在上一章回中介绍了PopupMenuButton相关的内容,它主…...
采用python中的opencv2的库来运用机器视觉移动物体
一. 此次我们来利用opencv2来进行机器视觉的学习 1. 首先我们先来进行一个小的案例的实现. 这次我们是将会进行一个小的矩形手势的移动. import cv2 from cvzone.HandTrackingModule import HandDetectorcap cv2.VideoCapture(0) # cap.set(3, 1280) # cap.set(4, 720) col…...
一、thymeleaf简介
1.1 什么是thymeleaf Thymeleaf是一个适用于web和独立环境的现代服务器端Java模板引擎,能够处理HTML、XML、JavaScript、CSS甚至纯文本。主要目标是提供一种优雅且高度可维护的创建模板的方法。 何为模板引擎呢?模板引擎就是为了使用户页面和业务数据…...
二分查找模版
对于一个递增序列我们要找大于等于target的数,返回结果的下标时 比如 序列 5 7 7 8 8 10 初始化左右指针l0 rn-1 猜测区间 [l,r] 闭区间,mid(lr)/2 防溢出就写成 midl(r-l)/2 如果有nums[mid]<target 那么[l,mid]这个区间的数就都小于target 更新 lmi…...
idea清空缓存类
解决办法 网上有很多是让你去清空什么maven依赖,但假如这个项目是你不可以大刀阔斧的话 可以清空idea缓存 选择 Invalidate 开头的 然后全选 运行重启idea OK...
PAT(Basic Level) Practice(中文) 1015德才论
前言 ※ PTA是 程序设计类实验辅助教学平台 ,里边包含一些编程题目集以供练习。 这道题用java解,我试了三种解法,不断优化,但始终是三个测试点通过、三个测试点超时。我把我的代码放在这里,做个参考吧。 1015 德才…...
接口自动化测试的概述及流程梳理~
接下来开始学习接口自动化测试。 因为之前从来没接触过,所以先了解一些基础知识。 1.接口测试的概述 2.接口自动化测试流程。 接口测试概述 接口,又叫API(Application Programming Interface,应用程序编程接口)&a…...
竞赛 机器视觉 opencv 深度学习 驾驶人脸疲劳检测系统 -python
文章目录 0 前言1 课题背景2 Dlib人脸识别2.1 简介2.2 Dlib优点2.3 相关代码2.4 人脸数据库2.5 人脸录入加识别效果 3 疲劳检测算法3.1 眼睛检测算法3.2 打哈欠检测算法3.3 点头检测算法 4 PyQt54.1 简介4.2相关界面代码 5 最后 0 前言 🔥 优质竞赛项目系列&#x…...
虚拟货币(也称为加密货币或数字货币)的运作
虚拟币发展史 虚拟币的发展史可以追溯到20世纪末和21世纪初,以下是虚拟币的重要发展节点: 1998年:比特币白皮书的发布 比特币的概念最早由中本聪(Satoshi Nakamoto)在1998年提出,随后在2008年发布了一份名…...
N. Number Reduction
Problem - 1765N - Codeforces 发现如果是无前导0最小数那么在保证删除k个数时第1位是最小的,第二位一定是相对最小的,且答案第一位和第二位在原位置的间隔是小于等于还可以删除的位数的。 因此,对于原数字长度位n,要删除k&#…...
Java集合面试题
一、Java集合面试题 1.LinkedHashMap底层原理? HashMap是无序的,迭代HashMap所得到元素的顺序并不是它们最初放到HashMap的顺序,即不能保持它们的插入顺序。 LinkedHashMap继承于HashMap,是HashMap和LinkedList的融合体&#x…...
Python 编程基础 | 第三章-数据类型 | 3.5、列表
一、列表 1、创建列表 序列是Python中最基本的数据结构,Python有6个序列的内置类型,但最常见的是列表和元组。序列都可以进行的操作包括索引,切片,加,乘,检查成员。此外,Python已经内置确定序列…...
Spring Cloud Zuul 基本原理
Spring Cloud Zuul 底层是基于Servlet实现的,核心是通过一系列的ZuulFilter来完成请求的转发。 1、核心组件注册 1.1. EnableZuulProxy注解 启用Zuul作为微服务网关,需要在Application应用类加上EnableZuulProxy注解,而该注解核心是利用Im…...
QT实现TCP服务器客户端的实现
ser: widget.cpp: #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);//实例化一个服务器server new QTcpServer(this);// 此时…...
行为型设计模式——责任链模式
摘要 责任链模式(Chain of responsibility pattern): 通过责任链模式, 你可以为某个请求创建一个对象链. 每个对象依序检查此请求并对其进行处理或者将它传给链中的下一个对象。 一、责任链模式意图 职责链模式(Chain Of Responsibility) 是一种行为设…...
window安装压缩版postgresql
环境: window 11 专业版postgresql-16.0-1-windows-x64-binaries.zip 一、下载 1.1 从官网下载 https://www.postgresql.org/download/windows/ 1.2 从百度网盘下载 链接:https://pan.baidu.com/s/1fmQbgWSzX4hN07Lgdzfz0g?pwddzyy 提取码&#…...
数组(数据结构)
优质博文:IT-BLOG-CN 一、简介 数组Array是一种线性表数据结构,它用一组连续的内存空间,存储一组具有相同类型的数据。 数组因具有连续的内存空间的特点,数据拥有非常高效率的“随机访问”,时间复杂度为O(1)。但因要保…...
自己做网站 套模板/网络推广项目外包公司
在配置百度地图 SDK 和使用时,发现官网上的教程并不是那么好用,而且容易出现定位回调里 BDLocation.getLocType() 162 这个问题,官网只是说 SO 配置出现异常,并没有明确问题所在;如果你也遇到了,请点这个链…...
做网站制作较好的公司/成都疫情最新消息
一.简介 0. 页面的生命周期。 1. WebForm后台页面类继承于Page类,Page类实现了IHttpHandler接口。 2. 前台页面类继承于后台页面类。 3. 先调用PageLoad方法,再调用Render方法生成html代码。 二. 加密安全 互联网没有绝对的安全,登…...
网页制作免费网站建设/管理培训
疑问:之前一直以为hashcode就是计算对象的内存地址,但是看其它博文又有说不是的,特此研究一下! 先说结论:在JDK1.8中,hashcode和对象的内存地址没有必然关系,不是hashcode相等,他们…...
wordpress get_search_form()/什么是百度搜索推广
MMA7660加速计驱动 1、MMA7660介绍 MMA7660FC 是一款数字输出 IC、超低功耗、薄型电容式微加工加速度计,具有低通滤波器、零重力偏移和增益误差补偿以及用户可配置输出数据转换为六位数字值速度。 该器件可通过中断引脚 (INT) 用于传感器数据更改、产品方向和手势检测。 I2C…...
网站开发的项目流程图/自媒体营销的策略和方法
词向量模型之CBOW模型的原理与实现关于词向量模型word2rec,平台里只有skip-gram一个模型的代码实现,本项目将对word2rec算法的第二个模型——CBOW模型进行补充此项目用于交流与学习,如有问题,请大家积极指出,作者将第一…...
床上做受网站/网站设计方案
MUI: http://dev.dcloud.net.cn/mui/snippet/ html5plus: http://www.html5plus.org/doc/h5p.html转载于:https://www.cnblogs.com/haitaoli/p/10520749.html...