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

MyBatis主键自增回填功能源码分析

文章目录

  • 难点分析
  • KeyGenerator接口
    • 概述
    • SelectKeyGenerator分析
  • 解析selectKey标签
  • 执行插入后执行获取主键查询

难点分析

【1】 事务的一致性。
在插入数据并获取自增主键时,可能会涉及事务的一致性问题,尤其是在并发插入的情况下。MyBatis需要确保即使在高并发的环境中,获取到的主键是正确的,避免产生重复或错误的主键。
【2】 数据库支持差异。
不同数据库的自增主键实现方式不同,这使得MyBatis必须对不同数据库有不同的处理方式。例如:
• MySQL:可以通过useGeneratedKeys=true来获取自增主键。
• Oracle:需要使用RETURNING INTO语句或通过Sequence获取主键。
• PostgreSQL:使用RETURNING子句来返回主键。
MyBatis需要根据数据库的不同来选择正确的获取主键的方式,因此数据库方言(Dialect)的设计至关重要。
【3】 配置和扩展性
MyBatis允许开发者通过自定义插件来扩展其功能,针对主键自增功能,开发者可能会希望自定义插入操作的行为,例如获取主键的方式或插入后处理。因此,MyBatis的设计需要考虑到灵活的配置选项,以便开发者根据需求调整主键自增的实现方式。
主键自增的配置与生效
MyBatis 中的 KeyGenerator 实现类共有三种:Jdbc3KeyGenerator、SelectKeyGenerator、NoKeyGenerator。在实际使用时,这三种实现类中只能有一种实现类生效。
要启用 Jdbc3KeyGenerator,可以在配置文件中增加配置。

在这里插入图片描述
或者直接在相关语句上启用 useGeneratedKeys

<insert id="insert" parameterType="cn.mybatis.test.po.User" useGeneratedKeys="true" keyProperty="id"></insert>

如果要启用 SelectKeyGenerator,则需要在 SQL语句前加一段 selectKey标签

<insert id="insert" parameterType="cn.mybatis.test.po.User" >INSERT INTO t_user ...<selectKey keyProperty="id" order="AFTER" resultType="long">SELECT LAST_INSERT_ID()</selectKey></insert>

如果某一条语句中同时设置了 useGeneratedKeys和 selectKey,则后者生效。

KeyGenerator接口

概述

在这里插入图片描述

public interface KeyGenerator {/*** 针对Sequence主键而言,在执行insert sql前必须指定一个主键值给要插入的记录,* 如Oracle、DB2,KeyGenerator提供了processBefore()方法。*/void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter);/*** 针对自增主键的表,在插入时不需要主键,而是在插入过程自动获取一个自增的主键,* 比如MySQL、PostgreSQL,KeyGenerator提供了processAfter()方法*/void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter);}

MyBatis 中的 KeyGenerator 实现类共有三种:Jdbc3KeyGenerator、SelectKeyGenerator、NoKeyGenerator。在实际使用时,这三种实现类中只能有一种实现类生效。
NoKeyGenerator:代表不具有任何的主键自增功能。
Jdbc3KeyGenerator:主要用于数据库的自增主键,如MySQL,PostgreSQL。
SelectKeyGenerator:主要用于数据库不支持自增主键的情况,如Oracle,DB2。

SelectKeyGenerator分析

SelectKeyGenerator类主要体现在processAfter方法对processGeneratedKeys的调用处理。

   private void processGeneratedKeys(Executor executor, MappedStatement ms, Object parameter) {try {if (parameter != null && keyStatement != null && keyStatement.getKeyProperties() != null) {String[] keyProperties = keyStatement.getKeyProperties();final Configuration configuration = ms.getConfiguration();final MetaObject metaParam = configuration.newMetaObject(parameter);if (keyProperties != null) {Executor keyExecutor = configuration.newExecutor(executor.getTransaction());List<Object> values = keyExecutor.query(keyStatement, parameter, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);if (values.size() == 0) {throw new RuntimeException("SelectKey returned no data.");} else if (values.size() > 1) {throw new RuntimeException("SelectKey returned more than one value.");} else {MetaObject metaResult = configuration.newMetaObject(values.get(0));if (keyProperties.length == 1) {if (metaResult.hasGetter(keyProperties[0])) {setValue(metaParam, keyProperties[0], metaResult.getValue(keyProperties[0]));} else {setValue(metaParam, keyProperties[0], values.get(0));}} else {handleMultipleProperties(keyProperties, metaParam, metaResult);}}}}} catch (Exception e) {throw new RuntimeException("Error selecting key or setting result to parameter object. Cause: " + e);}}

首先检查传入的 parameter 参数对象是否为 null,keyStatement 是否为 null,以及 keyStatement 中的 keyProperties 是否为 null。keyProperties 用来定义主键属性的字段名。Object parameter是执行Insert的参数对象,待回写主键的对象。

在这里插入图片描述
keyProperties是插入对象主键字段,比如userId。configuration 是 MyBatis 的配置对象,包含了 MyBatis 的配置信息。metaParam 是 parameter 对象的 MetaObject,用于通过反射操作 parameter 对象的字段。
ExecutorkeyExecutor= configuration.newExecutor(executor.getTransaction());

创建一个新的 Executor 对象,这个 Executor 用于执行查询语句(即获取主键的 SelectKey 语句)。它会共享当前事务 executor.getTransaction()。
对于MySQL来说是在执行插入SQL后,返回此条插入语句后的自增索引。当数据库中有俩条需要执行的SQL语句时,重点是必须在同一个数据源连接下,否则会失去事务的特性,如果不是在同一个数据源连接下,那么返回的自增ID的值将是0。

使用 keyExecutor 执行 keyStatement(一个 MappedStatement 对象,表示查询主键的 SQL 语句)并返回结果。parameter 作为查询参数传入,RowBounds.DEFAULT 表示没有分页,Executor.NO_RESULT_HANDLER 表示不使用结果处理器。

在这里插入图片描述
keyExecutor.query实际就是复用了Insert执行语句的事务连接,并在执行Insert后执行selectKey标签的SELECT LAST_INSERT_ID()获取刚才执行的自增主键。LAST_INSERT_ID() 是一个 MySQL 函数,用来返回最后插入的自增列的 ID。它会返回当前连接的最后一次插入操作生成的自增值。
如果查询返回了单个结果,将其封装成 MetaObject,并通过 keyProperties 设置到 parameter 对象中。如果 keyProperties 只有一个属性,通过 setValue 方法将主键值设置到 parameter 对象。如果 keyProperties 有多个属性,调用 handleMultipleProperties 方法来处理。
然后就将获取的主键值通过反射赋值到Object parameter对象的keyProperties字段属性上,最终完成主键值的回写。

解析selectKey标签

标签会在解析mapper xml的INSERT语句中进行处理。
cn.bugstack.mybatis.builder.xml.XMLStatementBuilder#parseStatementNode

    // Parse selectKey after includes and remove them.processSelectKeyNodes(id, parameterTypeClass, langDriver);
  private void processSelectKeyNodes(String id, Class<?> parameterTypeClass, LanguageDriver langDriver) {List<XNode> selectKeyNodes = context.evalNodes("selectKey");if (configuration.getDatabaseId() != null) {parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, configuration.getDatabaseId());}parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, null);removeSelectKeyNodes(selectKeyNodes);}
private void parseSelectKeyNode(String id, Element nodeToHandle, Class<?> parameterTypeClass, LanguageDriver langDriver) {String resultType = nodeToHandle.attributeValue("resultType");Class<?> resultTypeClass = resolveClass(resultType);boolean executeBefore = "BEFORE".equals(nodeToHandle.attributeValue("order", "AFTER"));String keyProperty = nodeToHandle.attributeValue("keyProperty");// defaultString resultMap = null;KeyGenerator keyGenerator = new NoKeyGenerator();// 解析成SqlSource,DynamicSqlSource/RawSqlSourceSqlSource sqlSource = langDriver.createSqlSource(configuration, nodeToHandle, parameterTypeClass);SqlCommandType sqlCommandType = SqlCommandType.SELECT;// 调用助手类builderAssistant.addMappedStatement(id,sqlSource,sqlCommandType,parameterTypeClass,resultMap,resultTypeClass,keyGenerator,keyProperty,langDriver);// 给id加上namespace前缀id = builderAssistant.applyCurrentNamespace(id, false);// 存放键值生成器配置MappedStatement keyStatement = configuration.getMappedStatement(id);configuration.addKeyGenerator(id, new SelectKeyGenerator(keyStatement, executeBefore));}

解析 MyBatis 配置中的 元素,构建一个用于获取生成主键的 SQL 语句,并将其作为 MappedStatement 注册到 MyBatis 配置中。它支持在插入操作之前或之后执行主键查询,并且能够将查询结果映射到指定的属性。

执行插入后执行获取主键查询

对于StatementHandler接口定义的方法,用于SQL语句执行时只有update和query,所以扩展的insert方法也是对update方法的扩展。
mybatis.executor.statement.PreparedStatementHandler#update

    @Overridepublic int update(Statement statement) throws SQLException {PreparedStatement ps = (PreparedStatement) statement;ps.execute();int rows = ps.getUpdateCount();Object parameterObject = boundSql.getParameterObject();KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);return rows;}

将传入的 Statement 对象转换为 PreparedStatement,因为更新操作通常使用预编译的 SQL 语句。使用 execute() 方法执行 SQL 语句。这里使用 execute() 而不是 executeUpdate(),可能是为了兼容多种类型的 SQL 语句。execute() 可以执行所有类型的 SQL 语句,包括更新、插入、删除和查询。

getUpdateCount() 返回的是通过执行 SQL 语句所影响的行数,即被更新、插入或删除的记录数。
mappedStatement 是与当前 SQL 语句相关联的 MappedStatement 对象,它包含了执行该 SQL 所需的所有配置信息。通过 getKeyGenerator() 获取与当前 SQL 语句关联的主键生成器(KeyGenerator),这个生成器负责处理主键的生成和设置。
keyGenerator.processAfter 是 MyBatis 中 KeyGenerator 接口的一个方法,表示在执行 SQL 更新语句后对主键进行处理。
executor 是 MyBatis 中负责执行 SQL 语句的执行器,mappedStatement 是当前的映射语句,ps 是执行的 PreparedStatement 对象,parameterObject 是执行 SQL 语句时传入的参数对象。这个方法用于将生成的主键值从数据库查询中获取,并将其设置到参数对象的相应属性中。

在执行 SQL 更新(插入)操作,并在执行后处理生成的主键,它通过执行 PreparedStatement 更新语句获取影响的行数,并通过主键生成器的 processAfter 方法获取数据库生成的主键,将其设置到参数对象的相应属性中,从而确保在执行插入或更新操作时,主键能够正确地回填到参数对象中,最终返回更新操作影响的行数,实现了 MyBatis 中主键生成与对象映射的自动化处理,
这里的关键在于它在执行 SQL 更新操作时,利用同一个事务连接(executor.getTransaction())来确保对数据库的操作保持一致性,并且通过主键生成器(KeyGenerator)在同一事务中处理主键回填问题。通过共用事务连接,MyBatis 保证了在执行插入或更新操作时,数据库生成的主键能够被正确获取并回填到参数对象中,同时不会发生跨事务的操作错误,从而实现了主键生成、事务一致性以及数据回填的自动化处理。

相关文章:

MyBatis主键自增回填功能源码分析

文章目录 难点分析KeyGenerator接口概述SelectKeyGenerator分析 解析selectKey标签执行插入后执行获取主键查询 难点分析 【1】 事务的一致性。 在插入数据并获取自增主键时&#xff0c;可能会涉及事务的一致性问题&#xff0c;尤其是在并发插入的情况下。MyBatis需要确保即使…...

Git使用教程-分支使用/合并分支提交

Git使用教程-分支使用 文章目录 Git使用教程-分支使用一、分支&#xff08;branch&#xff09;的基本操作&#xff1a;二、查看分支&#xff1a;参考 一、分支&#xff08;branch&#xff09;的基本操作&#xff1a; git clone https://.git git status …...

TypeScript概述与安装指南

TypeScript概述与安装指南 HarmonyOS Next主要开发语言是ArkTS&#xff0c;ArkTS又是TS的超集&#xff0c;为了更好的学习HarmonyOS 和 ArkTS&#xff0c;从基础的TS入口介绍TS语法。 第一章&#xff1a;TypeScript概述与安装指南 1.1 什么是TypeScript&#xff1f; TypeSc…...

学技术学英文:代码中的锁:悲观锁和乐观锁

本文导读&#xff1a; 1. 举例说明加锁的场景&#xff1a; 多线程并发情况下有资源竞争的时候&#xff0c;如果不加锁&#xff0c;会出现数据错误&#xff0c;举例说明&#xff1a; 业务需求&#xff1a;账户余额>取款金额&#xff0c;才能取钱。 时间线 两人共有账户 …...

Git配置公钥步骤

GIt公钥的配置去除了git push输入账号密码的过程&#xff0c;简化了push流程。 1.生成SSH公钥和私钥 ssh-keygen -t rsa -b 4096 -C “your_emailexample.com” 遇到的所有选项都按回车按默认处理。获得的公钥私钥路径如下&#xff1a; 公钥路径 : ~/.ssh/id_rsa.pub 私钥路径…...

NSDT 3DConvert:高效实现大模型文件在线预览与转换

NSDT 3DConvert 作为一个 WebGL 展示平台&#xff0c;能够实现多种模型格式免费在线预览&#xff0c;并支持大于1GB的OBJ、STL、GLTF、点云等模型进行在线查看与交互&#xff0c;这在3D模型展示领域是一个相当强大的功能。 平台特点 多格式支持 NSDT 3DConvert兼容多种3D模型…...

优先队列【东北大学oj数据结构9-3】C++

优先队列 优先级队列是一种数据结构&#xff0c;其中保存了一组数据 S&#xff0c;其中每个元素都有一个键&#xff0c;并执行以下操作&#xff1a; insert(S, k)&#xff1a;将元素k插入集合S extractMax(S)&#xff1a;从S中取出S中key最大的元素并返回其值 创建一个程序&am…...

全志H618 Android12修改doucmentsui功能菜单项

背景: 由于当前的文件管理器在我们的产品定义当中,某些界面有改动的需求,所以需要在Android12 rom中进行定制以符合当前产品定义。 需求: 在进入File文件管理器后,查看...功能菜单时,有不需要的功能菜单,需要隐藏,如:新建窗口、不显示的文件夹、故代码分析以及客制…...

SAP PP ECN CSAP_MAT_BOM_MAINTAIN

刚开始的时候ECN总是加不上&#xff0c; 参考kimi给出的案例 点击链接查看和 Kimi 智能助手的对话 https://kimi.moonshot.cn/share/cth1ipmqvl7f04qkggdg 效果 加上了 FUNCTION ZPBOM_PLM2SAP. *"------------------------------------------------------------------…...

STM32HAL I2C函数

8.5 使用IIC协议读写EEPROM 硬件方式实现 &#xff08;HAL库&#xff09; **HAL_I2C_Mem_Write() :这种方法可以写1个或者多个字节 ** /*** brief 以阻塞模式向指定的内存地址写入数据* param hi2c 指向 I2C_HandleTypeDef 结构体的指针&#xff0c;包含指定 I2C 的配置信息…...

技术转管理需要有哪些思维上的转变?

不少项目管理行业的负责人都是从技术岗产生&#xff0c;那么技术岗做的是代码、调试之类的内容&#xff0c;除了负责范围增加外&#xff0c;还有什么思维方面的转变呢&#xff1f; 1、从个体到团队 个体的技能决定着工作的完成度&#xff0c;而在管理工作岗位上&#xff0c;项…...

数据结构漫游记:初识vector

​ 嘿&#xff0c;各位技术潮人&#xff01;好久不见甚是想念。生活就像一场奇妙冒险&#xff0c;而编程就是那把超酷的万能钥匙。此刻&#xff0c;阳光洒在键盘上&#xff0c;灵感在指尖跳跃&#xff0c;让我们抛开一切束缚&#xff0c;给平淡日子加点料&#xff0c;注入满满的…...

RestTemplate远程调用、服务注册、

一.RestTemplate Spring给我们提供了一个RestTemplate的API&#xff0c;可以方便的实现Http请求的发送。 同步客户端执行HTTP请求&#xff0c;在底层HTTP客户端库(如JDK HttpURLConnection、Apache HttpComponents等)上公开一个简单的模板方法API。RestTemplate通过HTTP方法为常…...

ARP..

ARP 0 前言 真正接触到现网才发现ARP十分重要&#xff0c;无论是排错还是S-MLAG都需要用到ARP这个协议&#xff0c;以前对于ARP的理解比较混乱&#xff1b;所以这次对其中的主要内容做个梳理&#xff1b;一定要学好ARP&#xff01;&#xff01;&#xff01; 1 ARP的概念 Ar…...

电子电器架构 ---整车区域控制器

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所谓鸡汤,要么蛊惑你认命,要么怂恿你拼命,但都是回避问题的根源,以现象替代逻辑,以情绪代替思考,把消极接受现实的懦弱,伪装成乐观面对不幸的…...

HBase、Hive、Redis 和 MongoDB的对比

1. 数据库管理 操作HBaseHiveRedisMongoDB创建数据库N/A (HBase 没有数据库概念)CREATE DATABASE db_name;N/A (Redis 没有数据库命名功能)use db_name; (自动创建)查看数据库N/ASHOW DATABASES;INFO 查看全局信息show dbs;删除数据库N/ADROP DATABASE db_name CASCADE;N/Adb.…...

前端在WebSocket中加入Token

在WebSocket通信中加入Token主要是为了实现身份验证和授权&#xff0c;确保只有经过验证的用户可以建立WebSocket连接。由于WebSocket API本身不支持直接在连接时设置HTTP头部&#xff0c;因此需要采用一些变通的方法来传递Token。以下是几种常见的方法&#xff1a; 1、通过UR…...

图解HTTP-HTTP报文

参考资料&#xff1a;图解HTTP HTTP报文 用于HTTP协议交互的信息被称为HTTP报文。请求端的HTTP请求报文&#xff0c;响应端&#xff08;服务器端&#xff09;的叫做响应报文。HTTP报文本身是由多行&#xff08;CR LF作为换行符&#xff09;数据行构成的文本。 请求报文及响…...

后端使用Spring Boot框架 + 前端VUE 实现滑动模块验证码

在现在常用的登录验证码方式有很多种&#xff0c;但是都不可避免被攻击&#xff0c;但是有很多方式可以防止被攻击&#xff0c;从而进行维护。 现在我就讲解一下滑动块验证码的实现方式&#xff1a; 这个是前端代码&#xff0c;我使用的是vue&#xff0c;在使用的时候注意&am…...

NOTEBOOK_11 汽车电子设备分享(工作经验)

汽车电子设备分享 摘要 本文主要列出汽车电子应用的一些实验设备和生产设备&#xff0c;部分会给予一定推荐。目录 摘要一、通用工具&#xff1a;二、测量与测试仪器2.1测量仪器2.2无线通讯测量仪器2.3元器件测试仪2.4安规测试仪2.5电源供应器2.6电磁兼容测试设备2.7可靠性环境…...

Spring Mvc面试题(常见)

1 Spring MVC的执行流程 用户发起请求,请求先被Servlet拦截以后,转发给SpringMVC框架SpringMVC 里面的DispatcherServlet(核心控制器) 接收到请求,并转发给HandlerMappingHandlerMapping负责解析请求,根据请求信息和配置信息找到匹配的Controller类(当这里有配置拦截器,会…...

javaEE--计算机是如何工作的-1

目录 一.计算机的组成: 各组件的功能: 衡量cpu好坏的标准: 二.指令(instruction) 三.操作系统Operating System 四.进程/任务process/tesk 五.进程在系统中如何管理 1.进程在系统中的管理,从两个角度来分类: 2.进程控制块PCB&#xff08;Process Control Block)) 3.P…...

【Mysql】函数有哪些

mysql函数有哪些&#xff1f; MySQL 提供了许多内置函数&#xff0c;用于执行各种操作&#xff0c;包括字符串处理、日期时间操作、数学计算、数据转换等。以下是一些常用的 MySQL 函数分类及其示例&#xff1a; 字符串函数 CONCAT(str1, str2, ...)&#xff1a;将多个字符串…...

「Mac畅玩鸿蒙与硬件45」UI互动应用篇22 - 评分统计工具

本篇将带你实现一个评分统计工具&#xff0c;用户可以对多个选项进行评分。应用会实时更新每个选项的评分结果&#xff0c;并统计平均分。这一功能适合用于问卷调查或评分统计的场景。 关键词 UI互动应用评分统计状态管理数据处理多目标评分 一、功能说明 评分统计工具允许用…...

实验13 C语言连接和操作MySQL数据库

一、安装MySQL 1、使用包管理器安装MySQL sudo apt update sudo apt install mysql-server2、启动MySQL服务&#xff1a; sudo systemctl start mysql3、检查MySQL服务状态&#xff1a; sudo systemctl status mysql二、安装MySQL开发库 sudo apt-get install libmysqlcli…...

Azure虚拟机非托管磁盘大小调整

想要扩容一个Azure VM 的磁盘空间&#xff0c;门户里面竟然无法扩展&#xff0c;点点鼠标就完事的时代在离去&#xff0c;微软越来不想微软。 在门户里面即便使用Azure Cli命令行也不行。 PS /home/gpchina> az disk list [] 返回为空&#xff0c;根本没有返回磁盘。 不过使…...

MySQL数据库下载及安装教程

链接&#xff1a;MySQL数据库下载及安装教程&#xff08;最最新版&#xff09;_mysql下载安装-CSDN博客 亲测安装成功了&#x1f495; 把这个路径放到系统环境变量里头 MD!我这安到C盘去了&#xff0c;就很烦&#x1f92c;&#x1f621; 在CMD登录试一下 mysql -h localhos…...

使用 UniApp 在微信小程序中实现 SSE 流式响应

概述 服务端发送事件(Server-Sent Events, SSE)是一种允许服务器向客户端推送实时更新的技术。SSE 提供了一种单向的通信通道,服务器可以持续地向客户端发送数据,而不需要客户端频繁发起请求。这对于需要实时更新的应用场景非常有用。 流式传输的特点是将数据逐步传输给客…...

基础数据结构---栈

顺序表实现 一、栈类的声明 栈是一种特殊的线性表&#xff0c;可以由顺序表来实现&#xff0c;也可以由链表来实现&#xff0c;这节课&#xff0c;我们采用顺序表来实现栈。 #include <iostream>#include <stdexcept>using namespace std;template<typename …...

Redis 最佳实践

这是以前写下来的文章&#xff0c;发出来备份一下 Redis 在企业中的最佳实践可以帮助提高性能、可用性和数据管理效率。以下是一些推荐的做法&#xff1a; 选择合适的数据结构&#xff1a; 根据需求选择适当的 Redis 数据结构&#xff08;如 Strings、Lists、Sets、Hashes、So…...

前端零基础学习Day-Eight

CSS字体和文本样式 CSS文字样式 字体&#xff1a;font-family 语法&#xff1a;font-family:[字体1][,字体2][,…] p{font-family:“微软雅黑”,“宋体”,“黑体”;} 含空格字体名和中文&#xff0c;用英文引号括起 属性值&#xff1a;具体字体名&#xff0c;字体集 字体集&…...

在Vue3中实现文件上传功能,结合后端API

随着现代Web应用程序的不断发展&#xff0c;文件上传成为了用户交互中不可或缺的一部分。在本篇博客中&#xff0c;我们将深入讨论如何在Vue3中实现一个文件上传功能&#xff0c;并与后端API进行交互。我们将使用Vue3的Composition API&#xff08;setup语法糖&#xff09;来构…...

智慧商城:点击“加入购物车”判断是否登录来进行跳转到登录页登录并回跳 + 发请求渲染加入购物车数量的角标

点击“加入购物车”判断是否登录来进行跳转到登录页登录并回跳 按需引入需要的 Dialog 组件并进行全局注册 Vue.use( )仅仅在Vue组件的上下文中起作用&#xff0c;所以在Vue组件中通过 this.$ 来使用 在 js 文件中则还要导入&#xff0c;然后直接使用&#xff0c;并不需要 this…...

植物大战僵尸杂交版v3.0.2最新版本(附下载链接)

B站游戏作者潜艇伟伟迷于12月21日更新了植物大战僵尸杂交版3.0.2版本&#xff01;&#xff01;&#xff01;&#xff0c;有b站账户的记得要给作者三连关注一下呀&#xff01; 不多废话下载链接放上&#xff1a; 夸克网盘链接&#xff1a;&#xff1a;https://pan.quark.cn/s/5c…...

后端统一接口返回状态【初步模板】

后端统一接口返回状态【模板】 文章目录 后端统一接口返回状态【模板】1 .Result类编写2 .Constants类编写3 .更改Controller层下的类return格式 开发过程中&#xff0c;每个接口的返回格式设计都是一样的&#xff0c;这样可以大大提高开发效率。 项目结构如下图&#xff1a;分…...

QML Text组件

文章目录 前言主体基本文本显示字体和样式富文本支持长文本的处理文本样式与效果超链接Label 元素总结 前言 在 QML 中&#xff0c;Text 和 Label 是常用的文本显示元素&#xff0c;它们在显示文本方面具有相似性&#xff0c;但在功能和定制性上也存在一些差异。Text 元素用于…...

cv2.addWeighted用法详解

cv2.addWeighted 是 OpenCV 中用于图像加权叠加的函数&#xff0c;常用于将两张图像按一定比例融合在一起。它通过对两张图像的像素进行加权和求和的操作&#xff0c;可以实现透明度调整、图像混合、图像融合等效果。 函数定义 cv2.addWeighted(src1, alpha, src2, beta, gam…...

基于微信小程序的消防隐患在线举报系统

博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;熟悉各种主流语言&#xff0c;精通java、python、php、爬虫、web开发&#xff0c;已经做了多年的设计程序开发&#xff0c;开发过上千套设计程序&#xff0c;没有什么华丽的语言&#xff0c;只有实…...

牛客网 SQL36查找后排序

SQL36查找后排序 select device_id,age from user_profile order by age asc #select [字段1,字段2] from [表名] order by [字段1] [升序(asc)/降序(desc)],[字段2] [升序(asc)/降序(desc)] #select&#xff1a;查询 #order by 排序 每日问题 如何实现对象的克隆&#xff1…...

Dart 中的构造函数

在 Dart 中&#xff0c;类的构造函数用于初始化类的对象。当你创建一个类的实例时&#xff0c;构造函数被自动调用。Dart 支持多种构造函数的写法&#xff0c;包括常规构造函数、命名构造函数、工厂构造函数等。 一、传统构造函数 默认构造函数是没有名字的构造函数&#xff…...

实现 WebSocket 接入文心一言

目录 什么是 WebSocket&#xff1f; 为什么需要 WebSocket&#xff1f; HTTP 的局限性 WebSocket 的优势 总结&#xff1a;HTTP 和 WebSocket 的区别 WebSocket 的劣势 WebSocket 常见应用场景 WebSocket 握手过程 WebSocket 事件处理和生命周期 WebSocket 心跳机制 …...

GO--堆(have TODO)

堆 堆&#xff08;Heap&#xff09;是一种特殊的数据结构。它是一棵完全二叉树&#xff08;完全二叉树是指除了最后一层外&#xff0c;每一层上的节点数都是满的&#xff0c;并且最后一层的节点都集中在左边&#xff09;&#xff0c;结放在数组&#xff08;切片&#xff09;中…...

【Python随笔】Enigma密码机的原理及python代码实现

最近笔者接触到了Cypher这款游戏&#xff0c;玩法很简单&#xff0c;就是通过文字、图片等各种表达手段组成的谜面&#xff0c;猜一段英文&#xff0c;算是初步接触了密码学的一些知识。游戏中提到了很多类型的密码&#xff0c;其中Enigma密码机就是单独一种&#xff0c;在电影…...

二叉树 -- 堆(详解)

目录 1、堆的概念及结构 2、堆的实现(附代码) 2.1、向下调整算法建堆 3、堆的应用(附代码) 3.1、堆排序 3.2、TOP-K问题 1、堆的概念及结构 如果有一个关键码的集合K { k0&#xff0c;k1 &#xff0c;k2 &#xff0c;…&#xff0c;k(n-1) }&#xff0c;把它的所有元素…...

gradle项目下载依赖报错

报错信息 Cannot resolve external dependency org.projectlombok:lombok:1.18.36 because no repositories are defined. Required by:project :Possible solution:- Declare repository providing the artifact, see the documentation at https://docs.gradle.org/current/…...

WPS怎么都无法删除空白页_插入空白页一次插入两张?_插入横屏空白页_横屏摆放图片_这样解决_显示隐藏段落标记---WPS工作笔记001

在wps使用的过程中你们有没有碰到过这种问题,就是,我贴图,因为图片太大,我需要把图片,横屏显示,这个时候我需要插入一个空白页,那么,在空白菜单下,点击,有时候会点击插入空白页,会一下子自动插入两张空白页.而且,怎么删除都删除不掉. 都快疯掉了. 网上搜索也没有找到好的方法,后…...

flask before_request 请求拦截器返回无值则放行,有值则拦截

环境 Python 3.11.5 Flask 2.2.2完整代码如下&#xff1a; from flask import Flask, make_response, Blueprintapp Flask(__name__) user_blue Blueprint(user, __name__, url_prefix/api/user) user_blue.before_request def befor…...

前端XMLHttpRequest get请求能不能在body中传参数?

文档 查看mdn文档&#xff0c;文档XMLHttpRequest.send()有提到&#xff1a; XMLHttpRequest.send() 方法接受一个可选的参数&#xff0c;其作为请求主体&#xff1b;如果请求方法是 GET 或者 HEAD&#xff0c;则应将请求主体设置为 null。 测试 一个简单的nodejs服务器 var…...

C语言的函数指针

介绍案例 什么是函数指针&#xff1f; 函数指针 是指向函数的指针变量&#xff0c;它可以用来间接调用函数。在 C/C 中&#xff0c;函数指针允许程序在运行时选择调用不同的函数&#xff0c;这使得代码更加灵活和动态。函数指针广泛应用于回调函数、事件处理、动态选择算法等…...

网络安全的学习方向和路线是怎么样的?

石器时代 第一个阶段——石器时代&#xff0c;针对的是纯新手小白刚刚入场。在这个阶段&#xff0c;主要是打基础&#xff0c;需要学习的有五部分内容&#xff1a; Windows Windows上基础的一些命令、PowerShell的使用和简单脚本编写&#xff0c;以及Windows以后经常会打交道…...