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

MyBatis-Plus分页拦截器,源码的重构(重构total总数的计算逻辑)

 1.1创建ThreadLocal工具类(作为业务逻辑结果存放类)

package org.springblade.sample.utils;public class QueryContext {private static final ThreadLocal<Long> totalInThreadLocal = new ThreadLocal<>();public static void setTotalIn(long totalIn) {totalInThreadLocal.set(totalIn);}public static long getTotalIn() {return totalInThreadLocal.get() != null ? totalInThreadLocal.get() : 0;}public static void clear() {totalInThreadLocal.remove();}
}

2.1重构Mybatis-plus分页查询total总数逻辑(通过实现InnerInterceptor接口进行重构,代码如下,根据注释进行对应业务调整即可)

package org.springblade.sample.config;import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.*;
import com.baomidou.mybatisplus.extension.parser.JsqlParserGlobal;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.DialectFactory;
import com.baomidou.mybatisplus.extension.plugins.pagination.DialectModel;
import com.baomidou.mybatisplus.extension.plugins.pagination.dialects.IDialect;
import com.baomidou.mybatisplus.extension.toolkit.JdbcUtils;
import com.baomidou.mybatisplus.extension.toolkit.PropertyMapper;
import com.baomidou.mybatisplus.extension.toolkit.SqlParserUtils;
import groovy.util.logging.Slf4j;
import lombok.Data;
import lombok.NoArgsConstructor;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Alias;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.select.*;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.sample.utils.QueryContext;import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;/*** 分页拦截器* <p>* 默认对 left join 进行优化,虽然能优化count,但是加上分页的话如果1对多本身结果条数就是不正确的** @author hubin* @since 3.4.0*/
@lombok.extern.slf4j.Slf4j
@Data
@NoArgsConstructor
@org.springframework.context.annotation.Configuration
@Slf4j
public class PaginationInnerInterceptor implements InnerInterceptor {/*** 获取jsqlparser中count的SelectItem*/protected static final List<SelectItem> COUNT_SELECT_ITEM = Collections.singletonList(new SelectExpressionItem(new Column().withColumnName("COUNT(*)")).withAlias(new Alias("total")));protected static final Map<String, MappedStatement> countMsCache = new ConcurrentHashMap<>();protected final Log logger = LogFactory.getLog(this.getClass());/*** 表名*/private final String V_SAMPLE_COVID19 = "v_sample_covid19";private final String T_SAMPLE_COVID19 = "t_sample_covid19";private final String T_SAMPLE_FLU = "t_sample_flu";private final String T_SAMPLE_HADV = "t_sample_hadv";private final String T_SAMPLE_HMPV = "t_sample_hmpv";private final String T_SAMPLE_HPIV = "t_sample_hpiv";private final String T_SAMPLE_METAV = "t_sample_metav";private final String T_SAMPLE_RSV = "t_sample_rsv";/*** 溢出总页数后是否进行处理*/protected boolean overflow;/*** 单页分页条数限制*/protected Long maxLimit;/*** 数据库类型* <p>* 查看 {@link #findIDialect(Executor)} 逻辑*/private DbType dbType;/*** 方言实现类* <p>* 查看 {@link #findIDialect(Executor)} 逻辑*/private IDialect dialect;/*** 生成 countSql 优化掉 join* 现在只支持 left join** @since 3.4.2*/protected boolean optimizeJoin = true;public PaginationInnerInterceptor(DbType dbType) {this.dbType = dbType;}public PaginationInnerInterceptor(IDialect dialect) {this.dialect = dialect;}/**** 重构willDoQuery获取序列未上传数量(根据检索结果进行实时更新)* @param executor      Executor(可能是代理对象)* @param ms            MappedStatement* @param parameter     parameter* @param rowBounds     rowBounds* @param resultHandler resultHandler* @param boundSql      boundSql*/public boolean willDoQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {IPage<?> page = ParameterUtils.findPage(parameter).orElse(null);if (page == null || page.getSize() < 0 || !page.searchCount() || resultHandler != Executor.NO_RESULT_HANDLER) {return true;}BoundSql countSql;BoundSql countSqlIn;MappedStatement countMs = buildCountMappedStatement(ms, page.countId());if (countMs != null) {countSql = countMs.getBoundSql(parameter);countSqlIn = countMs.getBoundSql(parameter);} else {countMs = buildAutoCountMappedStatement(ms);String countSqlStr = autoCountSql(page, boundSql.getSql());PluginUtils.MPBoundSql mpBoundSql = PluginUtils.mpBoundSql(boundSql);countSql = new BoundSql(countMs.getConfiguration(), countSqlStr, mpBoundSql.parameterMappings(), parameter);countSqlIn = new BoundSql(countMs.getConfiguration(), countSqlStr + " and seq_num = '0'", mpBoundSql.parameterMappings(), parameter);PluginUtils.setAdditionalParameter(countSql, mpBoundSql.additionalParameters());PluginUtils.setAdditionalParameter(countSqlIn, mpBoundSql.additionalParameters());}// 执行第一个查询 (result)CacheKey cacheKey = executor.createCacheKey(countMs, parameter, rowBounds, countSql);List<Object> result = executor.query(countMs, parameter, rowBounds, resultHandler, cacheKey, countSql);long total = 0;if (CollectionUtils.isNotEmpty(result)) {// 个别数据库 count 没数据不会返回 0Object o = result.get(0);if (o != null) {total = Long.parseLong(o.toString());}}page.setTotal(total);long totalIn = 0;//获取表名String tableName = getTableFromSql(boundSql.getSql());// 执行第二个查询 (resultIn)if (StringUtil.isNotBlank(tableName)) {//根据表名判断是否进行查询if (this.suitTableName(tableName)) {CacheKey cacheKeyIn = executor.createCacheKey(countMs, parameter, rowBounds, countSqlIn);List<Object> resultIn = executor.query(countMs, parameter, rowBounds, resultHandler, cacheKeyIn, countSqlIn);log.info("未上传序列数:{}", Long.parseLong(resultIn.get(0).toString()));if (CollectionUtils.isNotEmpty(resultIn)) {// 个别数据库 count 没数据不会返回 0Object o = resultIn.get(0);if (o != null) {totalIn = Long.parseLong(o.toString());}}}}// 将 totalIn 设置到 ThreadLocal 中QueryContext.setTotalIn(totalIn);return continuePage(page);}@Overridepublic void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)  {IPage<?> page = ParameterUtils.findPage(parameter).orElse(null);if (null == page) {return;}// 处理 orderBy 拼接boolean addOrdered = false;String buildSql = boundSql.getSql();List<OrderItem> orders = page.orders();if (CollectionUtils.isNotEmpty(orders)) {addOrdered = true;buildSql = this.concatOrderBy(buildSql, orders);}// size 小于 0 且不限制返回值则不构造分页sqlLong _limit = page.maxLimit() != null ? page.maxLimit() : maxLimit;if (page.getSize() < 0 && null == _limit) {if (addOrdered) {PluginUtils.mpBoundSql(boundSql).sql(buildSql);}return;}handlerLimit(page, _limit);IDialect dialect = findIDialect(executor);final Configuration configuration = ms.getConfiguration();DialectModel model = dialect.buildPaginationSql(buildSql, page.offset(), page.getSize());PluginUtils.MPBoundSql mpBoundSql = PluginUtils.mpBoundSql(boundSql);List<ParameterMapping> mappings = mpBoundSql.parameterMappings();Map<String, Object> additionalParameter = mpBoundSql.additionalParameters();model.consumers(mappings, configuration, additionalParameter);mpBoundSql.sql(model.getDialectSql());mpBoundSql.parameterMappings(mappings);}/*** 获取分页方言类的逻辑** @param executor Executor* @return 分页方言类*/protected IDialect findIDialect(Executor executor) {if (dialect != null) {return dialect;}if (dbType != null) {dialect = DialectFactory.getDialect(dbType);return dialect;}return DialectFactory.getDialect(JdbcUtils.getDbType(executor));}/*** 获取指定的 id 的 MappedStatement** @param ms      MappedStatement* @param countId id* @return MappedStatement*/protected MappedStatement buildCountMappedStatement(MappedStatement ms, String countId) {if (StringUtils.isNotBlank(countId)) {final String id = ms.getId();if (!countId.contains(StringPool.DOT)) {countId = id.substring(0, id.lastIndexOf(StringPool.DOT) + 1) + countId;}final Configuration configuration = ms.getConfiguration();try {return CollectionUtils.computeIfAbsent(countMsCache, countId, key -> configuration.getMappedStatement(key, false));} catch (Exception e) {logger.warn(String.format("can not find this countId: [\"%s\"]", countId));}}return null;}/*** 构建 mp 自用自动的 MappedStatement** @param ms MappedStatement* @return MappedStatement*/protected MappedStatement buildAutoCountMappedStatement(MappedStatement ms) {final String countId = ms.getId() + "_mpCount";final Configuration configuration = ms.getConfiguration();return CollectionUtils.computeIfAbsent(countMsCache, countId, key -> {MappedStatement.Builder builder = new MappedStatement.Builder(configuration, key, ms.getSqlSource(), ms.getSqlCommandType());builder.resource(ms.getResource());builder.fetchSize(ms.getFetchSize());builder.statementType(ms.getStatementType());builder.timeout(ms.getTimeout());builder.parameterMap(ms.getParameterMap());builder.resultMaps(Collections.singletonList(new ResultMap.Builder(configuration, Constants.MYBATIS_PLUS, Long.class, Collections.emptyList()).build()));builder.resultSetType(ms.getResultSetType());builder.cache(ms.getCache());builder.flushCacheRequired(ms.isFlushCacheRequired());builder.useCache(ms.isUseCache());return builder.build();});}/*** 获取自动优化的 countSql** @param page 参数* @param sql  sql* @return countSql*/protected String autoCountSql(IPage<?> page, String sql) {if (!page.optimizeCountSql()) {return lowLevelCountSql(sql);}try {Select select = (Select) JsqlParserGlobal.parse(sql);SelectBody selectBody = select.getSelectBody();// https://github.com/baomidou/mybatis-plus/issues/3920  分页增加union语法支持if (selectBody instanceof SetOperationList) {return lowLevelCountSql(sql);}PlainSelect plainSelect = (PlainSelect) select.getSelectBody();Distinct distinct = plainSelect.getDistinct();GroupByElement groupBy = plainSelect.getGroupBy();// 包含 distinct、groupBy 不优化if (null != distinct || null != groupBy) {return lowLevelCountSql(select.toString());}// 优化 order by 在非分组情况下List<OrderByElement> orderBy = plainSelect.getOrderByElements();if (CollectionUtils.isNotEmpty(orderBy)) {boolean canClean = true;for (OrderByElement order : orderBy) {// order by 里带参数,不去除order byExpression expression = order.getExpression();if (!(expression instanceof Column) && expression.toString().contains(StringPool.QUESTION_MARK)) {canClean = false;break;}}if (canClean) {plainSelect.setOrderByElements(null);}}for (SelectItem item : plainSelect.getSelectItems()) {if (item.toString().contains(StringPool.QUESTION_MARK)) {return lowLevelCountSql(select.toString());}}// 包含 join 连表,进行判断是否移除 join 连表if (optimizeJoin && page.optimizeJoinOfCountSql()) {List<Join> joins = plainSelect.getJoins();if (CollectionUtils.isNotEmpty(joins)) {boolean canRemoveJoin = true;String whereS = Optional.ofNullable(plainSelect.getWhere()).map(Expression::toString).orElse(StringPool.EMPTY);// 不区分大小写whereS = whereS.toLowerCase();for (Join join : joins) {if (!join.isLeft()) {canRemoveJoin = false;break;}FromItem rightItem = join.getRightItem();String str = "";if (rightItem instanceof Table) {Table table = (Table) rightItem;str = Optional.ofNullable(table.getAlias()).map(Alias::getName).orElse(table.getName()) + StringPool.DOT;} else if (rightItem instanceof SubSelect) {SubSelect subSelect = (SubSelect) rightItem;/* 如果 left join 是子查询,并且子查询里包含 ?(代表有入参) 或者 where 条件里包含使用 join 的表的字段作条件,就不移除 join */if (subSelect.toString().contains(StringPool.QUESTION_MARK)) {canRemoveJoin = false;break;}str = subSelect.getAlias().getName() + StringPool.DOT;}// 不区分大小写str = str.toLowerCase();if (whereS.contains(str)) {/* 如果 where 条件里包含使用 join 的表的字段作条件,就不移除 join */canRemoveJoin = false;break;}for (Expression expression : join.getOnExpressions()) {if (expression.toString().contains(StringPool.QUESTION_MARK)) {/* 如果 join 里包含 ?(代表有入参) 就不移除 join */canRemoveJoin = false;break;}}}if (canRemoveJoin) {plainSelect.setJoins(null);}}}// 优化 SQLplainSelect.setSelectItems(COUNT_SELECT_ITEM);return select.toString();} catch (JSQLParserException e) {// 无法优化使用原 SQLlogger.warn("optimize this sql to a count sql has exception, sql:\"" + sql + "\", exception:\n" + e.getCause());} catch (Exception e) {logger.warn("optimize this sql to a count sql has error, sql:\"" + sql + "\", exception:\n" + e);}return lowLevelCountSql(sql);}/*** 无法进行count优化时,降级使用此方法** @param originalSql 原始sql* @return countSql*/protected String lowLevelCountSql(String originalSql) {return SqlParserUtils.getOriginalCountSql(originalSql);}/*** 查询SQL拼接Order By** @param originalSql 需要拼接的SQL* @return ignore*/public String concatOrderBy(String originalSql, List<OrderItem> orderList) {try {Select select = (Select) JsqlParserGlobal.parse(originalSql);SelectBody selectBody = select.getSelectBody();if (selectBody instanceof PlainSelect) {PlainSelect plainSelect = (PlainSelect) selectBody;List<OrderByElement> orderByElements = plainSelect.getOrderByElements();List<OrderByElement> orderByElementsReturn = addOrderByElements(orderList, orderByElements);plainSelect.setOrderByElements(orderByElementsReturn);return select.toString();} else if (selectBody instanceof SetOperationList) {SetOperationList setOperationList = (SetOperationList) selectBody;List<OrderByElement> orderByElements = setOperationList.getOrderByElements();List<OrderByElement> orderByElementsReturn = addOrderByElements(orderList, orderByElements);setOperationList.setOrderByElements(orderByElementsReturn);return select.toString();} else if (selectBody instanceof WithItem) {// todo: don't known how to resolereturn originalSql;} else {return originalSql;}} catch (JSQLParserException e) {logger.warn("failed to concat orderBy from IPage, exception:\n" + e.getCause());} catch (Exception e) {logger.warn("failed to concat orderBy from IPage, exception:\n" + e);}return originalSql;}protected List<OrderByElement> addOrderByElements(List<OrderItem> orderList, List<OrderByElement> orderByElements) {List<OrderByElement> additionalOrderBy = orderList.stream().filter(item -> StringUtils.isNotBlank(item.getColumn())).map(item -> {OrderByElement element = new OrderByElement();element.setExpression(new Column(item.getColumn()));element.setAsc(item.isAsc());element.setAscDescPresent(true);return element;}).collect(Collectors.toList());if (CollectionUtils.isEmpty(orderByElements)) {return additionalOrderBy;}// github pull/3550 优化排序,比如:默认 order by id 前端传了name排序,设置为 order by name,idadditionalOrderBy.addAll(orderByElements);return additionalOrderBy;}/*** count 查询之后,是否继续执行分页** @param page 分页对象* @return 是否*/protected boolean continuePage(IPage<?> page) {if (page.getTotal() <= 0) {return false;}if (page.getCurrent() > page.getPages()) {if (overflow) {//溢出总页数处理handlerOverflow(page);} else {// 超过最大范围,未设置溢出逻辑中断 list 执行return false;}}return true;}/*** 处理超出分页条数限制,默认归为限制数** @param page IPage*/protected void handlerLimit(IPage<?> page, Long limit) {final long size = page.getSize();if (limit != null && limit > 0 && (size > limit || size < 0)) {page.setSize(limit);}}/*** 处理页数溢出,默认设置为第一页** @param page IPage*/protected void handlerOverflow(IPage<?> page) {page.setCurrent(1);}@Overridepublic void setProperties(Properties properties) {PropertyMapper.newInstance(properties).whenNotBlank("overflow", Boolean::parseBoolean, this::setOverflow).whenNotBlank("dbType", DbType::getDbType, this::setDbType).whenNotBlank("dialect", ClassUtils::newInstance, this::setDialect).whenNotBlank("maxLimit", Long::parseLong, this::setMaxLimit).whenNotBlank("optimizeJoin", Boolean::parseBoolean, this::setOptimizeJoin);}protected String getTableFromSql(String sql) {String regex = "(?i)from\\s+([a-zA-Z0-9_]+)";Pattern pattern = Pattern.compile(regex);Matcher matcher = pattern.matcher(sql);if (matcher.find()) {return matcher.group(1);}return null;}/*** 判断是否进行未上传序列数计算* @param tableName 表名*/private boolean suitTableName(String tableName) {switch (tableName) {case V_SAMPLE_COVID19:case T_SAMPLE_RSV:case T_SAMPLE_COVID19:case T_SAMPLE_FLU:case T_SAMPLE_HADV:case T_SAMPLE_HMPV:case T_SAMPLE_HPIV:case T_SAMPLE_METAV:return true;default:return false;}}
}

相关文章:

MyBatis-Plus分页拦截器,源码的重构(重构total总数的计算逻辑)

1.1创建ThreadLocal工具类&#xff08;作为业务逻辑结果存放类&#xff09; package org.springblade.sample.utils;public class QueryContext {private static final ThreadLocal<Long> totalInThreadLocal new ThreadLocal<>();public static void setTotalIn…...

记一MySQL连接速度慢的问题

某一个程序启动速度超级慢&#xff0c;查看日志得知是是在Init DruidDataSource ~ {dataSource-1} inited 这一段耗时最长&#xff0c;这一段是Druid 数据源初始化&#xff0c;进行连接的创建等&#xff0c;使用mysql命令行连接发现连接超级慢&#xff0c;可见是在创建连接的时…...

asp.net core webapi项目中 在生产环境中 进不去swagger

builder.WebHost.UseUrls 是 ASP.NET Core 中配置应用程序监听 URL 或端口的方法。通过使用这个方法&#xff0c;你可以指定应用程序应该在哪些 URL 上运行&#xff0c;以便接收 HTTP 请求。 1.在appsetting.json中 添加 "LaunchUrl": "http://*:327"2.在…...

逆向攻防世界CTF系列63-secret-string-400

逆向攻防世界CTF系列63-secret-string-400 丢入exeinfo&#xff0c;查得zip&#xff0c;解压得四个文件 点进Task&#xff0c;查看源码&#xff1a;Test your luck! Enter valid string and you will know flag 顺理成章地看js 定位check函数 调用了machine的loadcode 跟进…...

Datawhale AI 冬令营学习笔记-零编程基础制作井字棋小游戏

井字棋小游戏是通过豆包MarsCode实现的&#xff0c;没有改动任何的代码&#xff0c;全部是通过对话让AI进行优化和改进。 开始进入正题&#xff1a;进入豆包MarsCode在线IDE&#xff0c;直接点击上方蓝字&#xff0c;或复制链接打开: 豆包 MarsCode - 编程助手。 IDE界面&…...

分布式专题(10)之ShardingSphere分库分表实战指南

一、ShardingSphere产品介绍 Apache ShardingSphere 是一款分布式的数据库生态系统&#xff0c; 可以将任意数据库转换为分布式数据库&#xff0c;并通过数据分片、弹性伸缩、加密等能力对原有数据库进行增强。Apache ShardingSphere 设计哲学为 Database Plus&#xff0c;旨在…...

clickhouse解决suspiciously many的异常

1. 问题背景 clickhouse安装在虚拟机上&#xff0c;持续写入日志时&#xff0c;突然关机&#xff0c;然后重启&#xff0c;会出现clickhouse可以正常启动&#xff0c;但是查询sql语句&#xff0c;提示suspiciously many异常&#xff0c;如图所示 2. 问题修复 touch /data/cl…...

计算机的错误计算(一百九十)

摘要 用两个大模型计算cot(1.234). 其中&#xff0c;1.234是以弧度为单位的角度。结果保留10位有效数字。实验表明&#xff0c;两个的计算公式虽然不同&#xff0c;但是都是正确的。然而&#xff0c;数值计算则是有问题的---包括每一个中间运算与结果。 例1. 计算cot(1.234)…...

STM32-笔记12-实现SysTick模拟多线程流水灯

1、前言 正常STM32实现多线程&#xff0c;需要移植一个操作系统FreeRTOS。但是在这里不移植FreeRTOS怎么实现多线程呢&#xff1f;使用SysTick&#xff0c;那么怎么使用SysTick来模拟多线程呢&#xff1f;前面我们知道SysTick就是一个定时器&#xff0c;它不是在主函数的while循…...

牛客网刷题 ——C语言初阶——BC114 小乐乐排电梯

1.牛客网 &#xff1a;BC114 小乐乐排电梯 题目描述&#xff1a; 小乐乐学校教学楼的电梯前排了很多人&#xff0c;他的前面有n个人在等电梯。电梯每次可以乘坐12人&#xff0c;每次上下需要的时间为4分钟&#xff08;上需要2分钟&#xff0c;下需要2分钟&#xff09;。请帮助…...

web三、 window对象,延时器,定时器,时间戳,location对象(地址),本地存储-localStorage,数组去重new Set

一、window对象 window对象 是一个全局对象&#xff0c;也可以说是JavaScript中的 顶级对象 像document、alert()、console.log()这些都是window的属性&#xff0c;基本BOM的属性和方法都是window的 所有通过 var定义 在全局作用域中的 变量 、 函数 都会变成window对象的属…...

【EthIf-13】EthIfGeneral容器配置-01

1.EthIfGeneral类图结构 下面是EthIfGeneral配置参数的类图&#xff0c;比较重要的参数就是配置&#xff1a; 接收中断是否打开发送确认中断是否打开EthIf轮询周期 1.EthIfGeneral参数的含义...

‘pnpm’ 不是内部或外部命令,也不是可运行的程序或批处理文件。

‘pnpm’ 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件。 1.情况: npm -v 和 node -v的都正常就是 pnpm-v 无效 检查环境变量也没看出问题 2.分析 没有正确添加环境变量 3.解决 找到npm的全局安装目录 npm list -g --depth 0这里出现了npm的全局安装…...

ECMAScript 6-11 概述

1. ECMA 介绍 ECMA&#xff08;European Computer Manufacturers Association&#xff09;是欧洲计算机制造商协会&#xff0c;目标是评估、开发和认可电信和计算机标准。1994年后改名为Ecma国际。 2. ECMAScript 是什么 ECMAScript 是由Ecma国际通过ECMA-262标准化的脚本程…...

sqlalchemy连接dm8 get_columns BIGINT VARCHAR字段不显示

问题 标题即为问题&#xff0c; 问题出现原因 sqlalchemy对应的sqlalchemy_dm源码需要调整 版本说明 python 3.10 dmPython 2.5.5(2.4.8也可以) sqlalchemy1.4.52 sqlalchemy_dm1.4.39 环境说明 部署环境 ubuntu20 开发环境window11 wsl2 ubuntu20 可能会出现的…...

运动控制卡网络通讯的心跳检测之C#上位机编程

本文导读 今天&#xff0c;正运动小助手给大家分享一下如何使用C#上位机编程实现运动控制卡网络通讯的心跳检测功能。 01 ECI2618B硬件介绍 ECI2618B经济型多轴运动控制卡是一款脉冲型、模块化的网络型运动控制卡。控制卡本身最多支持6轴&#xff0c;可扩展至12轴的运动控制…...

QT 控件定义为智能指针引发的bug

问题描述&#xff1a; std::unique_ptr<QStackedLayout> m_stacked_layout; 如上为定义&#xff1b; 调用&#xff1a; Line13ABClient::Line13ABClient(QWidget *parent) : BaseWidget(parent) { // 成员变量初始化 m_get_ready false; m_tittle_wnd…...

Scala项目(图书管理系统)

3、service BookService package org.app package serviceimport org.app.dao.{BookDAO, BorrowRecordDAO} import org.app.models.{BookModel, BorrowRecordModel}import java.time.LocalDateTime import scala.collection.mutable.ListBuffer// 图书业务逻辑层 class BookS…...

前端开发 详解 Node. js 都有哪些全局对象?

在 Node.js 中&#xff0c;全局对象&#xff08;Global Objects&#xff09;是指在任何模块中都可以直接访问的对象和变量&#xff0c;而不需要显式地进行导入。Node.js 提供了一些全局对象&#xff0c;帮助开发者在编写应用程序时更加方便地进行一些常见操作&#xff0c;如文件…...

2024_12_20_生活记录

年底了&#xff0c;提前祝各位朋友们新年快乐&#xff01;我将近两年没动笔写blog了&#xff0c;主要确实挺忙。。。今天想简单聊聊自己的近期想法&#xff0c;一方面是职业规划&#xff0c;一方面是生信&#xff0c;最后是个人感悟。 职业规划 熟悉我的朋友们会了解我之前一直…...

Sequelize ORM 现有表如何使用

一、 在mysql中创建一个表 或者随便找一个现有的表 已经有了一张叫做xw_posts的表。表里的字段非常简单&#xff0c;大家可以自己建一下 CREATE TABLE xw_posts (id int unsigned NOT NULL AUTO_INCREMENT,name varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_…...

ArcGIS Pro 3.4新功能3:空间统计新特性,基于森林和增强分类与回归,过滤空间自相关

目录 应用 1&#xff1a;它是相关性还是托布勒第一定律&#xff1f; 应用 2&#xff1a;将空间带入非空间模型 结论 在 ArcGIS Pro 3.4 中&#xff0c;我们在新的空间组件实用程序&#xff08;Moran 特征向量&#xff09;工具集中发布了一个新工具 - 从字段过滤空间自相关。…...

H3C MPLS跨域optionB

实验拓扑 实验需求 如图,VPN1 和 VPN2 分别通过运营商 MPLS VPN 连接各自分支机构按照图示配置 IP 地址,VPN1 和 VPN2 连接同一个 PE 设备的私网 IP 网段存在地址复用,使用多 VRF 技术来防止 IP 冲突AS 100 和 AS 200 内部的公共网络中各自运行 OSPF 使 AS 内各设备的 Loo…...

源码分析之Openlayers中Geometry基类介绍

概述 在上一篇文章源码分析之Openlayers中Geom篇中提到Geometry类是继承于 Openlayers 中的BaseObject类(参考源码分析之Openlayers中核心BaseObject类).而Geometry类通常情况下也是作为一个抽象基类,作为Geom几何图形的基类或父类,不会在应用中去实例化它.Geometry类回去注册…...

《Vue3 三》Vue 中的 options 选项

data 选项&#xff1a; data 选项&#xff1a;属性值必须是一个函数&#xff1b;返回值是一个对象&#xff0c;返回的对象会被 Vue 的响应式系统劫持&#xff0c;之后对该对象的任何访问或者修改都会在劫持中被处理。 在 Vue2.x 中&#xff0c;data 的属性值可以是一个函数&am…...

Elasticsearch 国产化替代方案之一 Easysearch 的介绍与部署指南

一、前言 在国内数字化转型浪潮和 信创 大背景下&#xff0c;“替代进口”成为许多企业级应用所需要面对的重要课题&#xff0c;搜索领域也不例外。 Elasticsearch&#xff08;简称 ES&#xff09;作为一款业界领先的全文搜索和分析引擎&#xff0c;虽然功能强大&#xff0c;但…...

Pytorch | 从零构建EfficientNet对CIFAR10进行分类

Pytorch | 从零构建EfficientNet对CIFAR10进行分类 CIFAR10数据集EfficientNet设计理念网络结构性能特点应用领域发展和改进 EfficientNet结构代码详解结构代码代码详解MBConv 类初始化方法前向传播 forward 方法 EfficientNet 类初始化方法前向传播 forward 方法 训练过程和测…...

Python超能力:高级技巧让你的代码飞起来

文章一览 前言一、with1.1 基本用法1.2 示例自定义上下文管理器 二、条件表达式三、列表式推导式与 zip 结合 四、map() 函数&#xff08;内置函数&#xff09;map用于数据清洗1. 数据清洗&#xff1a;字母大小写规范2. filter() 函数 五、匿名函数 lambda5.1 lambda的参数&…...

熊军出席ACDU·中国行南京站,详解SQL管理之道

12月21日&#xff0c;2024 ACDU中国行在南京圆满收官&#xff0c;本次活动分为三个篇章——回顾历史、立足当下、展望未来&#xff0c;为线上线下与会观众呈现了一场跨越时空的技术盛宴&#xff0c;吸引了众多业内人士的关注。云和恩墨副总经理熊军出席此次活动并发表了主题演讲…...

FPGA实现MIPI转FPD-Link车载同轴视频传输方案,基于IMX327+FPD953架构,提供工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐本博主所有FPGA工程项目-->汇总目录我这里已有的 MIPI 编解码方案 3、本 MIPI CSI-RX IP 介绍4、详细设计方案设计原理框图IMX327 及其配置FPD-Link视频串化-解串方案MIPI CSI RX图像 ISP 处理图像缓存HDMI输出工程源码架构 5、…...