使用MybatisPlus实现sql日志打印优化
背景:
在排查无忧行后台服务日志时,一个请求可能会包含多个执行的sql,经常会遇到SQL语句与对应参数不连续显示,或者参数较多需要逐个匹配的情况。这种情况下,如果需要还原完整SQL语句就会比较耗时。因此,我希望能优化这一流程。
正文:
在平时排查sql执行情况时,对于sql查询参数比较多或者多个sql在同一个请求下执行的时候会比较麻烦,需要查看每个参数的值一一对应检查是否有异常,有时候还需要将查询sql的问号还原去库里面查询结果,就类似下面的日志:
一个一个参数还原比较麻烦,因此针对这种问题,我找到了一个解决办法,重写MybatisPlus的InnerInterceptor,将sql日志重新组装,那么在查看sql日志时候就可以直接查看赋值好参数的sql了,将上面截图的sql整合之后可以转化为下面的sql:
具体的思路以及实现方案,以无忧行项目为例
实现思路,利用mybatisplus提供的接口InnerInterceptor,重写sql日志,并将重写之后的类注入到sqlSessionFactory中,在执行sql之前捕获到并打印。
解释一下InnerInterceptor类:InnerInterceptor 是 MyBatis-Plus 框架中的一个核心拦截器接口,它是 MyBatis 拦截器机制的扩展,用于在 SQL 执行过程中进行拦截和增强。
InnerInterceptor工作原理:InnerInterceptor 通过 MyBatis 的插件机制工作,在以下时机进行拦截:
- beforeQuery:查询操作执行前
- beforeUpdate:更新操作执行前
- beforePrepare:SQL 准备阶段
针对查询sql执行的sql重整,使用的是beforeQuery,针对更新sql执行的重整,使用的是beforeUpdate,以下是具体实现:
1.首先,添加依赖,
maven依赖:
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.0</version>
</dependency>
或者gradle依赖:
compile("com.baomidou:mybatis-plus-generator:3.4.0")
2.重写InnerInterceptor
package com.cmi.jego.micro.flight.admin.service.config;import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandlerRegistry;import java.sql.SQLException;
import java.text.DateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;/*** sql日志重写** @author zhouxy* @date 2025年05月08日 11:27*/
@Slf4j
@org.springframework.context.annotation.Configuration
public class MybatisPlusLogRewrite implements InnerInterceptor {@Overridepublic void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {log.info("beforeQuery");logInfo(boundSql, ms, parameter);}@Overridepublic void beforeUpdate(Executor executor, MappedStatement ms, Object parameter) throws SQLException {log.info("beforeUpdate");BoundSql boundSql = ms.getBoundSql(parameter);logInfo(boundSql, ms, parameter);}private static void logInfo(BoundSql boundSql, MappedStatement ms, Object parameter) {try {// 获取到节点的id,即sql语句的idString sqlId = ms.getId();// 获取节点的配置Configuration configuration = ms.getConfiguration();// 获取到最终的sql语句String sql = getSql(configuration, boundSql, sqlId);log.info("完整的sql:{}", sql);} catch (Exception e) {log.error("异常:{}", e.getLocalizedMessage(), e);}}// 封装了一下sql语句,使得结果返回完整xml路径下的sql语句节点id + sql语句public static String getSql(Configuration configuration, BoundSql boundSql, String sqlId) {return sqlId + ":" + showSql(configuration, boundSql);}// 进行?的替换public static String showSql(Configuration configuration, BoundSql boundSql) {// 获取参数Object parameterObject = boundSql.getParameterObject();List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
// log.info("boundSql:{}",boundSql.getSql());// sql语句中多个空格都用一个空格代替String sql = boundSql.getSql().replaceAll("[\\s]+", " ");if (CollectionUtils.isNotEmpty(parameterMappings) && parameterObject != null) {// 获取类型处理器注册器,类型处理器的功能是进行java类型和数据库类型的转换TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();// 如果根据parameterObject.getClass()可以找到对应的类型,则替换if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {sql = sql.replaceFirst("\\?",Matcher.quoteReplacement(getParameterValue(parameterObject)));} else {// MetaObject主要是封装了originalObject对象,提供了get和set的方法用于获取和设置originalObject的属性值,主要支持对JavaBean、Collection、Map三种类型对象的操作MetaObject metaObject = configuration.newMetaObject(parameterObject);for (ParameterMapping parameterMapping : parameterMappings) {String propertyName = parameterMapping.getProperty();if (metaObject.hasGetter(propertyName)) {Object obj = metaObject.getValue(propertyName);sql = sql.replaceFirst("\\?",Matcher.quoteReplacement(getParameterValue(obj)));} else if (boundSql.hasAdditionalParameter(propertyName)) {// 该分支是动态sqlObject obj = boundSql.getAdditionalParameter(propertyName);sql = sql.replaceFirst("\\?",Matcher.quoteReplacement(getParameterValue(obj)));} else {// 打印出缺失,提醒该参数缺失并防止错位sql = sql.replaceFirst("\\?", "缺失");}}}}return sql;}// 如果参数是String,则添加单引号, 如果是日期,则转换为时间格式器并加单引号; 对参数是null和不是null的情况作了处理private static String getParameterValue(Object obj) {String value;if (obj instanceof String) {value = "'" + obj.toString() + "'";} else if (obj instanceof Date) {DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT,DateFormat.DEFAULT, Locale.CHINA);value = "'" + formatter.format(new Date()) + "'";} else {if (obj != null) {value = obj.toString();} else {value = "";}}return value;}
}
3.将当前的重写类MybatisPlusLogRewrite注入到sqlSessionFactory中。
package com.cmi.jego.micro.flight.admin.service.config;import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;import javax.annotation.PostConstruct;
import java.util.List;/*** @author zhouxy* @date 2025年05月09日 15:58*/
@Configuration
public class MyBatisPlusConfig {@Autowiredprivate List<SqlSessionFactory> sqlSessionFactoryList;@Autowiredprivate MybatisPlusLogRewrite myInnerInterceptor;/*** 添加Mybatis拦截器** @author zhouxy* @date 2025/5/15 16:29*/@PostConstructpublic void addMybatisInterceptor() {for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {org.apache.ibatis.session.Configuration configuration = sqlSessionFactory.getConfiguration();//将sql拦截器添加到MybatisPlusInterceptor拦截器链MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();mybatisPlusInterceptor.addInnerInterceptor(myInnerInterceptor);configuration.addInterceptor(mybatisPlusInterceptor);}}
}
关闭其他sql打印日志,执行查询sql,只打印当前重写之后的sql日志如下:
2025-05-14 18:03:01.353 INFO 34718 --- [ main] c.c.j.m.f.a.service.handler.LogHandler : function:[OrderRefundServiceImpl.queryOrderListStatusCount], request: {"lang":"zh_CN","pageNum":1,"pageSize":10}
2025-05-14 18:03:01.385 INFO 34718 --- [ main] c.c.j.m.f.a.s.c.MybatisPlusLogRewrite : beforeQuery
2025-05-14 18:03:01.387 INFO 34718 --- [ main] c.c.j.m.f.a.s.c.MybatisPlusLogRewrite : 完整的sql:com.cmi.jego.micro.flight.admin.service.mapper.jegotrip.TicketRefundMapper.queryListStatusCount:select distinct(tr.id) as refundId, tr.status from ticket_refund tr left join ticket_order td on tr.order_id = td.order_id left join ticket_passenger tp on tr.order_id = tp.order_id left join ticket_order_detail tod on tr.order_id = tod.order_id WHERE ( td.search_channel in ( 'hbgj-api-domestic-custom' ) or (td.order_source is null and td.search_channel is null) or td.order_source = '0' )
2025-05-14 18:03:01.395 WARN 34718 --- [ main] c.a.druid.pool.DruidAbstractDataSource : discard long time none received connection. , jdbcUrl : jdbc:mysql://localhost:3306/ticket_jegotrip?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8, version : 1.2.5, lastPacketReceivedIdleMillis : 263261
2025-05-14 18:03:01.395 WARN 34718 --- [ main] c.a.druid.pool.DruidAbstractDataSource : discard long time none received connection. , jdbcUrl : jdbc:mysql://localhost:3306/ticket_jegotrip?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8, version : 1.2.5, lastPacketReceivedIdleMillis : 263912
2025-05-14 18:03:01.396 WARN 34718 --- [ main] c.a.druid.pool.DruidAbstractDataSource : discard long time none received connection. , jdbcUrl : jdbc:mysql://localhost:3306/ticket_jegotrip?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8, version : 1.2.5, lastPacketReceivedIdleMillis : 263933
2025-05-14 18:03:01.396 WARN 34718 --- [ main] c.a.druid.pool.DruidAbstractDataSource : discard long time none received connection. , jdbcUrl : jdbc:mysql://localhost:3306/ticket_jegotrip?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8, version : 1.2.5, lastPacketReceivedIdleMillis : 263958
2025-05-14 18:03:01.396 WARN 34718 --- [ main] c.a.druid.pool.DruidAbstractDataSource : discard long time none received connection. , jdbcUrl : jdbc:mysql://localhost:3306/ticket_jegotrip?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2B8, version : 1.2.5, lastPacketReceivedIdleMillis : 263986
2025-05-14 18:03:01.851 INFO 34718 --- [ main] c.c.j.m.f.a.s.c.MybatisPlusLogRewrite : beforeQuery
2025-05-14 18:03:01.851 INFO 34718 --- [ main] c.c.j.m.f.a.s.c.MybatisPlusLogRewrite : 完整的sql:com.cmi.jego.micro.flight.admin.service.mapper.jegotrip.TicketRefundMoneyMapper.queryFailedByRefundIds:SELECT id , order_id, user_id, refund_id, pay_order_id, supplier_order_id, type, price, refund_price, status, refund_time, limit_time, refund_no, create_time, update_time, remark FROM ticket_refund_money WHERE refund_id IN ( 1295 , 1296 , 1423 , 1424 ) AND status = 4
2025-05-14 18:03:01.871 INFO 34718 --- [ main] c.c.j.m.f.a.service.handler.LogHandler : class:[OrderRefundServiceImpl.queryOrderListStatusCount] response: {"bizCode":0,"bizMsg":"SUCCESS","data":{"statusCounts":[{"count":1,"status":-1,"statusDesc":"已取消"},{"count":2,"status":3,"statusDesc":"已退票退款"},{"count":1,"status":4,"statusDesc":"退票异常"}]},"rpcCode":0,"rpcMsg":"SUCCESS"}, cost: 521,
2025-05-14 18:03:01.876 INFO 34718 --- [ main] c.c.j.m.f.a.s.s.OrderRefundServiceTest : {"bizCode":0,"bizMsg":"SUCCESS","data":{"statusCounts":[{"count":1,"status":-1,"statusDesc":"已取消"},{"count":2,"status":3,"statusDesc":"已退票退款"},{"count":1,"status":4,"statusDesc":"退票异常"}]},"rpcCode":0,"rpcMsg":"SUCCESS"}
性能评估方面
重写InnerInterceptor类其实是在SqlSessionFactory中添加了拦截器,那么性能如何呢?下面是我这边实际测试的时长对比
不添加sql重写:
添加sql重写:
根据测试时间可以看出,加了sql重写会比未加的时候的时间长了11ms。
因为涉及到拦截以及反射,性能比不加的时候会稍微耗时一些,
如果是访问量不高的情况下,用户对于加没加sql重写的主观感应时长其实差不多,因此这种sql重写方案适合后台访问并发量不高的情况使用。
如果是并发量较高且比较注重性能的情况下,不建议加。
相关文章:
使用MybatisPlus实现sql日志打印优化
背景: 在排查无忧行后台服务日志时,一个请求可能会包含多个执行的sql,经常会遇到SQL语句与对应参数不连续显示,或者参数较多需要逐个匹配的情况。这种情况下,如果需要还原完整SQL语句就会比较耗时。因此,我…...
HarmonyOS5云服务技术分享--ArkTS开发Node环境
✨ 你好呀,开发者小伙伴们!今天我们来聊聊如何在HarmonyOS(ArkTS API 9及以上)中玩转云函数,特别是结合Node.js和HTTP触发器的开发技巧。文章会手把手带你从零开始,用最接地气的方式探索这个功能࿰…...
水利数据采集MCU水资源的智能守护者
水利数据采集仪MCU,堪称水资源的智能守护者,其重要性不言而喻。在水利工程建设和水资源管理领域,MCU数据采集仪扮演着不可或缺的角色。它通过高精度的传感器和先进的微控制器技术,实时监测和采集水流量、水位、水质等关键数据&…...
深度学习之用CelebA_Spoof数据集搭建一个活体检测-用MNN来推理时候如何利用Conan对软件包进行管理
我为什么用Conan 前面的文章:深度学习之用CelebA_Spoof数据集搭建一个活体检测-训练好的模型用MNN来推理有提到怎么使用MNN对训练好的模型进行推理,里面并没有提到我是怎么编译和进行代码依赖包的管理的详细步骤,在这里我是用的是Conan:一个…...
深入解剖 G1 收集器的分区模型与调优策略
JVM 垃圾收集系列之三 | 高并发低延迟系统的首选 GC 解法! 一、为什么我们需要 G1 垃圾收集器? 在传统 GC(如 CMS)中,我们常常面临的问题是: GC 停顿不可预测(Stop-The-World)内存…...
兰亭妙微・UI/UX 设计・全链路开发
【遇见专业设计,共筑卓越产品】 在数字化浪潮中,界面是产品与用户对话的第一窗口。 兰亭妙微(蓝蓝设计),自 2008 年深耕 UI/UX 领域,以清华团队为核心,16 年专注软件与互联网产品的界面设计开…...
Babylon.js学习之路《六、材质与纹理:为模型赋予真实的表面效果》
文章目录 1. 引言:材质与纹理的重要性1.1 材质与纹理的核心作用 2. 基础材质:StandardMaterial2.1 材质属性详解2.2 实战:创建金属材质 3. 纹理贴图:从基础到高级3.1 基础纹理映射3.2 多纹理混合技术 4. 高级材质:PBRM…...
飞致云旗下开源项目GitHub Star总数突破150,000个
2025年5月19日,中国领先的开源软件提供商飞致云宣布,其旗下开源项目在代码托管平台GitHub上所获得的Star总数已经超过150,000个。基于在开源领域的长期耕耘和探索,飞致云的开源势能不断增强,获得第一个五万GitHub Star用时89个月&…...
萌新联赛第(三)场
C题 这道题用暴力去写想都不要想,一定超时,于是我们需要优化,下面是思路过程: 如图,本题只需找到x的因数个数和(n-x)的因数个数,这两个相乘,得到的就是对于这个x来说组合的个数,且x…...
cplex12.9 安装教程以及下载
cplex 感觉不是很好找,尤其是教育版,我这里提供一个版本,在下面的图可以看到,不仅可以配置matlab,也可以配置vs,现在拿vs2017来测试一下,具体文件的文件有需要的可以复制下面的链接获取 我用网盘分享了「c…...
Pycharm-jupyternotebook不渲染
解决方案: https://youtrack.jetbrains.com/issue/PY-54244 import plotly.io as pio pio.renderers.default "vscode"...
layui 介绍
layui(谐音:类 UI) 是一套开源的 Web UI 解决方案,采用自身经典的模块化规范,并遵循原生 HTML/CSS/JS 的开发方式,极易上手,拿来即用。其风格简约轻盈,而组件优雅丰盈,从源代码到使用…...
大数据相关操作
大数据相关操作 一、环境配置 1、修改主机名 #修改主机名 hostnamectl set-hostname master2、固定IP地址 # 进入修改 sudo vim /etc/netplan/01-network-manager-all.yaml# 修改配置文件 # Let NetworkManager manage all devices on this system network:version: 2rend…...
谷歌宣布推出 Android 的新安全功能,以防止诈骗和盗窃
在上周二的 Android Show 上,也就是Google I/O 开发者大会之前,谷歌宣布了 Android 的全新安全和隐私功能。这些新功能包括对通话、屏幕共享、消息、设备访问和系统级权限的全新保护。谷歌希望通过这些功能保护用户免遭诈骗,在设备被盗或被攻…...
WSL虚拟机整体迁移教程(如何将WSL从C盘迁移到其他盘)
文章目录 WSL虚拟机迁移教程一、查看当前主机的子系统二、导出 WSL 子系统三、将打包好的文件发送给另一个人四、在另一台机器导入并恢复子系统五、附加命令六、注意事项和导出文件信息6.1 注意事项6.2 导出文件信息使用 wsl --export 命令导出整个 WSL 子系统时,它…...
汽车区域电子电气架构(Zonal E/E)的统一
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 钝感力的“钝”,不是木讷、迟钝,而是直面困境的韧劲和耐力,是面对外界…...
开源一个记账软件,支持docker一键部署
欢迎来到我的博客,代码的世界里,每一行都是一个故事 🎏:你只管努力,剩下的交给时间 🏠 :小破站 开源一个记账软件,支持docker一键部署 项目简介功能特性技术栈快速开始环境要求运行步…...
新能源汽车焊接智能节气阀
在新能源汽车产业迅猛发展的浪潮中,制造工艺的优劣直接关系到车辆的性能、安全与市场竞争力。焊接,作为新能源汽车生产流程里的关键一环,无论是构建车身框架,还是连接电池模组,其质量的好坏都起着决定性作用。而在焊接…...
React 第四十四节Router中 usefetcher的使用详解及注意事项
前言 useFetcher 是 React Router 中一个强大的钩子,用于在不触发页面导航的情况下执行数据加载(GET)或提交(POST)。 一、useFetcher 应用场景: 1、后台数据预加载(如鼠标悬停时加载数据&…...
33、魔法防御术——React 19 安全攻防实战
一、奥术护盾(基础防御) 1. 敏感数据加密术 // cryptoUtils.js - 数据加密工具export const encrypt (data) > {// 实际项目应使用Web Crypto API或crypto-jsreturn btoa(encodeURIComponent(data));};export const decrypt (data) > {try {…...
NVM 安装与配置指南
简介 Node Version Manager(NVM)是一个常用的 Node.js 版本管理工具,可用于在开发过程中方便地切换不同版本的 Node.js。通过 NVM,用户可以根据项目需求选择不同的 Node.js 版本,而无需手动安装和卸载多个版本的 Node…...
SpringMVC04所有注解按照使用位置划分| 按照使用层级划分(业务层、视图层、控制层)
目录 一、所有注解按照使用位置划分(类、方法、参数) 1. 类级别注解 2. 方法级别注解 3. 参数级别注解 4. 字段/返回值注解 二、按照使用层级划分(业务层、视图层、控制层) 1、控制层(Controller Layer&#x…...
【数据库】-1 mysql 的安装
文章目录 1、mysql数据库1.1 mysql数据库的简要介绍 2、mysql数据库的安装2.1 centos安装2.2 ubuntu安装 1、mysql数据库 1.1 mysql数据库的简要介绍 MySQL是一种开源的关系型数据库管理系统(RDBMS),由瑞典MySQL AB公司开发,目前…...
MySQL与Redis一致性问题分析
一、一致性问题概述 1.1 什么是一致性问题? 在数据库-缓存架构中,当MySQL中的数据(最新值)与Redis缓存中的数据(缓存旧值)出现差异时,由于程序总是优先读取Redis缓存,就会导致应用…...
Xshell传输文件
新建文件 点击新建 完善主机地址 然后输入我们的远端服务器的SSH协议 一般的是这样的ssh -p 44562 rootregion-1.autodl.com 由于Xshell比较特殊我们输入ssh rootregion-1.autodl.com 44562这样的形式 然后输入服务器的密码即可...
怎样用 esProc 为大主子表关联提速
类似订单和明细表这样的主子表关联比较常见,在 SQL 中,这种关联用 JOIN 实现,在两个表都很大的情况下,常常出现计算速度非常慢的现象。 如果预先将主子表都按照主键有序存储,就可以使用归并算法实现关联。这种算法只需…...
打卡day31
文件的规范拆分和写法 知识点回顾 规范的文件命名规范的文件夹管理机器学习项目的拆分编码格式和类型注解 作业:尝试针对之前的心脏病项目,准备拆分的项目文件,思考下哪些部分可以未来复用。 导入依赖库 # 忽视警告 import warnings warn…...
编译原理的部分概念
解释程序:边解释边执行:不断读取源程序的语句,解释语句,读取此语句需要的数据,根据执行结果读取下一条语句,继续解释执行,直到返回结果。 编译程序:将源程序完整地转换成机器语言程…...
Java中字符串(String类)的常用方法
以下是Java中字符串(String类)的常用方法分类详解,包含核心方法说明和示例代码: 一、字符串基础信息 方法说明示例输出length()返回字符串长度"Hello".length()5isEmpty()判断字符串是否为空(长度是否为0&a…...
什么是 ERP,中国企业如何科学应用 ERP
中国企业在引入 ERP 系统过程中,常因盲目跟风大型企业选型、忽视自身业务适配性,导致系统功能过剩、实施成本高企、员工接受度低等问题,最终造成项目成功率不足 10%。因此,理性认知 ERP 的价值定位与本土化实施路径,成…...
使用SQLite Expert个人版VACUUM功能修复数据库
使用SQLite Expert个人版VACUUM功能修复数据库 一、SQLite Expert工具简介 SQLite Expert 是一款功能强大的SQLite数据库管理工具,分为免费的个人版(Personal Edition)和收费的专业版(Professional Edition)。其核心功…...
同源策略深度防御指南:CSP 高级应用与企业微信全场景适配(含 report-uri 实战)
一、CSP 核心指令权威解析与企业微信适配 内容安全策略(CSP)通过Content-Security-Policy响应头实现资源加载的细粒度控制,其核心指令与企业微信场景强相关: 1.1 frame-ancestors:iframe 嵌入源控制 权威规范&#…...
【AGI】大模型微调技术-四大微调框架
【AGI】大模型微调技术-四大微调框架 (1)微调基础概念介绍1.1 微调基本概念1.2 全量微调与高效微调1.3 模型微调的优劣势分析1.4 高效微调与LoRA、QLoRA (2)高效微调的应用场景(3)流微调工具介绍3.1 unslot…...
小白编程学习之巧解「消失的数字」
一、引言:一个看似简单的「找不同」问题 今天遇到一道有趣的算法题:给定一个含 n 个整数的数组 nums,其中每个元素都在 [1, n] 范围内,要求找出所有在 [1, n] 中但未出现在数组中的数字。 这让我想起小时候玩的「找错题」游戏 —…...
在 Git 中添加子模块(submodule)的详细步骤
在 Git 中添加子模块(submodule)的详细步骤如下: 1. 添加子模块 命令格式: git submodule add <仓库URL> [目标路径]仓库URL:子模块的 Git 仓库地址(HTTP/SSH 均可)。目标路径ÿ…...
瑞萨单片机笔记
1.CS for CC map文件中显示变量地址 Link Option->List->Output Symbol information 2.FDL库函数 pfdl_status_t R_FDL_Write(pfdl_u16 index, __near pfdl_u08* buffer, pfdl_u16 bytecount) pfdl_status_t R_FDL_Read(pfdl_u16 index, __near pfdl_u08* buffer, pfdl_…...
单片机复用功能重映射Remap功能
目录 一、查看“DS5319 stm32f10x中等密度mcu数据手册(英文)”手册 二、查看“RM0008 STM32F10xxx参考手册(中文)”手册 三、重映射(Remap)功能程序编写 自己学习过程中容易遗忘的知识点,记录…...
小白入门FPGA设计,如何快速学习?
很多刚入门的小伙伴,初次听说FPGA(现场可编程门阵列),脑子里只有一个字:玄! 什么“时序逻辑”“Verilog”“Vivado”,仿佛一夜之间掉进了电子黑魔法的深坑。 但真相是—— FPGA,其实…...
友思特应用 | LCD显示屏等玻璃行业的OCT检测应用
导读 光学相干层析成像(OCT)是一种非侵入式光学成像方法,提供微米尺度的空间分辨率,能够生成内部结构截面图像。自20世纪90年代初发明第一台OCT以来,它在眼科领域得到了广泛应用,并成为临床诊断的黄金标准之一。除了在生物医学领…...
Python的sys模块:系统交互的关键纽带
Python的sys模块:系统交互的关键纽带 对话实录 小白:(挠头)我知道 Python 能做很多事,可怎么让它和计算机系统‘交流’呢,比如获取系统信息、处理命令行参数? 专家:(微…...
若依项目集成sentinel、seata和shardingSphere
集成组件包括MySQL分库分表及读写分离、seata以及Sentinel 若依项目文档连接 代码下载地址 需要结合ruoyi代码配合看,前提是熟悉基本代码结构,熟悉feign调用和基础网关配置等。 采用的版本信息 <java.version>1.8</java.version> <spr…...
张 推进对话式心理治疗:SOULSPEAK的聊天机器人
SOULSPEAK的聊天机器人 利用大语言模型(LLM)来提供低成本的心理治疗服务,旨在解决传统心理咨询在隐私、成本和可及性方面的不足。以下是核心内容的通俗解读: 1. 研究背景:传统心理治疗的困境 问题:全球心理健康问题日益严重(如焦虑、抑郁人数激增),但传统心理咨询受…...
java中的Filter使用详解
Filter(过滤器)是 Java Web 开发的核心组件之一,用于在请求到达 Servlet 或响应返回客户端之前进行拦截和处理。以下是其核心功能、使用方法和实际场景的详细解析: 一、Filter 的作用与原理 核心作用 Filter 充当请求与响应之间的…...
BERT 作为Transformer的Encoder 为什么采用可学习的位置编码
摘要 BERT 在位置编码上与原始 Transformer 论文中的 sin/cos 公式不同,选择了可学习(learned)的位置嵌入方案。本文将从 Transformer 原始位置编码选项入手,分析 BERT 选择 learned positional embeddings 的四大核心原因&#x…...
Vue百日学习计划Day43-45天详细计划-Gemini版
Day 43: Composable 函数基础与抽取简单逻辑 (~3 小时) 本日目标: 理解 Composable 函数的概念、优势,并学会如何将简单的、无状态的逻辑抽取为 Composable。所需资源: Vue 3 官方文档 (组合式函数): https://cn.vuejs.org/guide/reusability/composables.html 学…...
Kotlin 协程 (二)
Kotlin 协程提供了丰富的功能,能够高效地处理并发和异步任务。以下是对 Kotlin 协程中常见概念和功能的详细讲解,包括它们的定义、作用、使用场景以及最佳实践。 1. 协程核心概念 1.1 CoroutineScope 定义:CoroutineScope 是协程作用域的抽…...
Linux 下 rsync 工具详解与实用指南
Linux 下 rsync 工具详解与实用指南 一、什么是 rsync? rsync(remote sync)是 Linux/Unix 系统下常用的数据同步和备份工具。它可以高效地在本地与远程主机之间同步文件和目录,支持增量同步、断点续传、权限保留等功能ÿ…...
2025年医美行业报告60+份汇总解读 | 附 PDF 下载
原文链接:https://tecdat.cn/?p42122 医美行业在消费升级与技术迭代的双重驱动下,已从边缘市场逐步走向主流。数据显示,2024 年中国医美市场规模突破 3000 亿元,年复合增长率达 15%,但行业仍面临正品率不足、区域发展…...
汉得集星獭1.8.0正式发布,高效集成再赋能!
汉得企业级系统集成平台 (中文名集星獭,英文名JeeStar)1.8.0版本于2025年4月正式发布 。 集星獭是一款一站式多系统集成、多云集成、多端集成、多协议集成、多设备集成、数据集成、页面集成的全域集成解决方案产品。 此次发布主要聚焦于以下…...
一文深度解析:Pump 与 PumpSwap 的协议机制与技术差异
在 Solana 链上,Pump.fun 和其延伸产品 PumpSwap 构成了 meme coin 发行与流通的两大核心场景。从初期的游戏化发行模型,到后续的自动迁移与交易市场,Pump 系列协议正在推动 meme coin 从“爆发性投机”走向“协议化运营”。本文将从底层逻辑…...