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

聊聊mybatis-plus的sql加载顺序

本文主要研究一下如果mybatis mapper定义了多个同名方法会不会有问题

MybatisConfiguration

com/baomidou/mybatisplus/core/MybatisConfiguration.java

    /*** MybatisPlus 加载 SQL 顺序:* <p> 1、加载 XML中的 SQL </p>* <p> 2、加载 SqlProvider 中的 SQL </p>* <p> 3、XmlSql 与 SqlProvider不能包含相同的 SQL </p>* <p>调整后的 SQL优先级:XmlSql > sqlProvider > CurdSql </p>*/@Overridepublic void addMappedStatement(MappedStatement ms) {if (mappedStatements.containsKey(ms.getId())) {/** 说明已加载了xml中的节点; 忽略mapper中的 SqlProvider 数据*/logger.error("mapper[" + ms.getId() + "] is ignored, because it exists, maybe from xml file");return;}mappedStatements.put(ms.getId(), ms);}

MybatisSqlSessionFactoryBean

com/baomidou/mybatisplus/extension/spring/MybatisSqlSessionFactoryBean.java

    /*** Build a {@code SqlSessionFactory} instance.* <p>* The default implementation uses the standard MyBatis {@code XMLConfigBuilder} API to build a* {@code SqlSessionFactory} instance based on an Reader. Since 1.3.0, it can be specified a* {@link Configuration} instance directly(without config file).* </p>** @return SqlSessionFactory* @throws IOException if loading the config file failed*/protected SqlSessionFactory buildSqlSessionFactory() throws Exception {//......if (this.mapperLocations != null) {if (this.mapperLocations.length == 0) {LOGGER.warn(() -> "Property 'mapperLocations' was specified but matching resources are not found.");} else {for (Resource mapperLocation : this.mapperLocations) {if (mapperLocation == null) {continue;}try {XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),targetConfiguration, mapperLocation.toString(), targetConfiguration.getSqlFragments());xmlMapperBuilder.parse();} catch (Exception e) {throw new IOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);} finally {ErrorContext.instance().reset();}LOGGER.debug(() -> "Parsed mapper file: '" + mapperLocation + "'");}}}}

MybatisSqlSessionFactoryBean的buildSqlSessionFactory方法会根据mapperLocations的配置取加载xml配置,即加载xml的mapper信息

XMLMapperBuilder

org/apache/ibatis/builder/xml/XMLMapperBuilder.java

  public void parse() {if (!configuration.isResourceLoaded(resource)) {configurationElement(parser.evalNode("/mapper"));configuration.addLoadedResource(resource);bindMapperForNamespace();}parsePendingResultMaps();parsePendingCacheRefs();parsePendingStatements();}private void bindMapperForNamespace() {String namespace = builderAssistant.getCurrentNamespace();if (namespace != null) {Class<?> boundType = null;try {boundType = Resources.classForName(namespace);} catch (ClassNotFoundException e) {// ignore, bound type is not required}if (boundType != null && !configuration.hasMapper(boundType)) {// Spring may not know the real resource name so we set a flag// to prevent loading again this resource from the mapper interface// look at MapperAnnotationBuilder#loadXmlResourceconfiguration.addLoadedResource("namespace:" + namespace);configuration.addMapper(boundType);}}}

XMLMapperBuilder的parse方法会执行configurationElement,即加载xml的mapper方法,之后执行bindMapperForNamespace,加载对应java mapper的方法

MybatisMapperRegistry

com/baomidou/mybatisplus/core/MybatisMapperRegistry.java

    @Overridepublic <T> void addMapper(Class<T> type) {if (type.isInterface()) {if (hasMapper(type)) {// TODO 如果之前注入 直接返回return;// TODO 这里就不抛异常了
//                throw new BindingException("Type " + type + " is already known to the MapperRegistry.");}boolean loadCompleted = false;try {// TODO 这里也换成 MybatisMapperProxyFactory 而不是 MapperProxyFactoryknownMappers.put(type, new MybatisMapperProxyFactory<>(type));// It's important that the type is added before the parser is run// otherwise the binding may automatically be attempted by the// mapper parser. If the type is already known, it won't try.// TODO 这里也换成 MybatisMapperAnnotationBuilder 而不是 MapperAnnotationBuilderMybatisMapperAnnotationBuilder parser = new MybatisMapperAnnotationBuilder(config, type);parser.parse();loadCompleted = true;} finally {if (!loadCompleted) {knownMappers.remove(type);}}}}

MybatisMapperRegistry通过MybatisMapperAnnotationBuilder进行parse

MybatisMapperAnnotationBuilder

com/baomidou/mybatisplus/core/MybatisMapperAnnotationBuilder.java

    public void parse() {String resource = type.toString();if (!configuration.isResourceLoaded(resource)) {loadXmlResource();configuration.addLoadedResource(resource);String mapperName = type.getName();assistant.setCurrentNamespace(mapperName);parseCache();parseCacheRef();IgnoreStrategy ignoreStrategy = InterceptorIgnoreHelper.initSqlParserInfoCache(type);for (Method method : type.getMethods()) {if (!canHaveStatement(method)) {continue;}if (getAnnotationWrapper(method, false, Select.class, SelectProvider.class).isPresent()&& method.getAnnotation(ResultMap.class) == null) {parseResultMap(method);}try {// TODO 加入 注解过滤缓存InterceptorIgnoreHelper.initSqlParserInfoCache(ignoreStrategy, mapperName, method);parseStatement(method);} catch (IncompleteElementException e) {// TODO 使用 MybatisMethodResolver 而不是 MethodResolverconfiguration.addIncompleteMethod(new MybatisMethodResolver(this, method));}}// TODO 注入 CURD 动态 SQL , 放在在最后, because 可能会有人会用注解重写sqltry {// https://github.com/baomidou/mybatis-plus/issues/3038if (GlobalConfigUtils.isSupperMapperChildren(configuration, type)) {parserInjector();}} catch (IncompleteElementException e) {configuration.addIncompleteMethod(new InjectorResolver(this));}}parsePendingMethods();}

这里通过反射获取对应java mapper的方法(这里的顺序是先接口本身定义的方法,然后是逐层继承的接口定义的方法),然后挨个执行parseStatement,接着执行parserInjector来处理内置的通过SqlMethod提供的内置方法

parseStatement

    private static final Set<Class<? extends Annotation>> statementAnnotationTypes = Stream.of(Select.class, Update.class, Insert.class, Delete.class, SelectProvider.class, UpdateProvider.class,InsertProvider.class, DeleteProvider.class).collect(Collectors.toSet());void parseStatement(Method method) {final Class<?> parameterTypeClass = getParameterType(method);final LanguageDriver languageDriver = getLanguageDriver(method);getAnnotationWrapper(method, true, statementAnnotationTypes).ifPresent(statementAnnotation -> {final SqlSource sqlSource = buildSqlSource(statementAnnotation.getAnnotation(), parameterTypeClass, languageDriver, method);final SqlCommandType sqlCommandType = statementAnnotation.getSqlCommandType();final Options options = getAnnotationWrapper(method, false, Options.class).map(x -> (Options) x.getAnnotation()).orElse(null);final String mappedStatementId = type.getName() + StringPool.DOT + method.getName();final KeyGenerator keyGenerator;String keyProperty = null;String keyColumn = null;if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) {// first check for SelectKey annotation - that overrides everything elseSelectKey selectKey = getAnnotationWrapper(method, false, SelectKey.class).map(x -> (SelectKey) x.getAnnotation()).orElse(null);if (selectKey != null) {keyGenerator = handleSelectKeyAnnotation(selectKey, mappedStatementId, getParameterType(method), languageDriver);keyProperty = selectKey.keyProperty();} else if (options == null) {keyGenerator = configuration.isUseGeneratedKeys() ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;} else {keyGenerator = options.useGeneratedKeys() ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;keyProperty = options.keyProperty();keyColumn = options.keyColumn();}} else {keyGenerator = NoKeyGenerator.INSTANCE;}Integer fetchSize = null;Integer timeout = null;StatementType statementType = StatementType.PREPARED;ResultSetType resultSetType = configuration.getDefaultResultSetType();boolean isSelect = sqlCommandType == SqlCommandType.SELECT;boolean flushCache = !isSelect;boolean useCache = isSelect;if (options != null) {if (FlushCachePolicy.TRUE.equals(options.flushCache())) {flushCache = true;} else if (FlushCachePolicy.FALSE.equals(options.flushCache())) {flushCache = false;}useCache = options.useCache();fetchSize = options.fetchSize() > -1 || options.fetchSize() == Integer.MIN_VALUE ? options.fetchSize() : null; //issue #348timeout = options.timeout() > -1 ? options.timeout() : null;statementType = options.statementType();if (options.resultSetType() != ResultSetType.DEFAULT) {resultSetType = options.resultSetType();}}String resultMapId = null;if (isSelect) {ResultMap resultMapAnnotation = method.getAnnotation(ResultMap.class);if (resultMapAnnotation != null) {resultMapId = String.join(StringPool.COMMA, resultMapAnnotation.value());} else {resultMapId = generateResultMapName(method);}}assistant.addMappedStatement(mappedStatementId,sqlSource,statementType,sqlCommandType,fetchSize,timeout,// ParameterMapIDnull,parameterTypeClass,resultMapId,getReturnType(method),resultSetType,flushCache,useCache,// TODO gcode issue #577false,keyGenerator,keyProperty,keyColumn,statementAnnotation.getDatabaseId(),languageDriver,// ResultSetsoptions != null ? nullOrEmpty(options.resultSets()) : null);});}

parseStatement这里解析带有Select.class, Update.class, Insert.class, Delete.class, SelectProvider.class, UpdateProvider.class, InsertProvider.class, DeleteProvider.class注解的方法,然后通过assistant.addMappedStatement注册到configuration的mappedStatements中,key为statementId(type.getName() + StringPool.DOT + method.getName())

parserInjector

com/baomidou/mybatisplus/core/MybatisMapperAnnotationBuilder.java

    void parserInjector() {GlobalConfigUtils.getSqlInjector(configuration).inspectInject(assistant, type);}

com/baomidou/mybatisplus/core/injector/AbstractSqlInjector.java

    @Overridepublic void inspectInject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass) {Class<?> modelClass = ReflectionKit.getSuperClassGenericType(mapperClass, Mapper.class, 0);if (modelClass != null) {String className = mapperClass.toString();Set<String> mapperRegistryCache = GlobalConfigUtils.getMapperRegistryCache(builderAssistant.getConfiguration());if (!mapperRegistryCache.contains(className)) {TableInfo tableInfo = TableInfoHelper.initTableInfo(builderAssistant, modelClass);List<AbstractMethod> methodList = this.getMethodList(mapperClass, tableInfo);if (CollectionUtils.isNotEmpty(methodList)) {// 循环注入自定义方法methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass, tableInfo));} else {logger.debug(mapperClass.toString() + ", No effective injection method was found.");}mapperRegistryCache.add(className);}}}

com/baomidou/mybatisplus/core/injector/AbstractMethod.java

    public void inject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {this.configuration = builderAssistant.getConfiguration();this.builderAssistant = builderAssistant;this.languageDriver = configuration.getDefaultScriptingLanguageInstance();/* 注入自定义方法 */injectMappedStatement(mapperClass, modelClass, tableInfo);}protected MappedStatement addInsertMappedStatement(Class<?> mapperClass, Class<?> parameterType, String id,SqlSource sqlSource, KeyGenerator keyGenerator,String keyProperty, String keyColumn) {return addMappedStatement(mapperClass, id, sqlSource, SqlCommandType.INSERT, parameterType, null,Integer.class, keyGenerator, keyProperty, keyColumn);}protected MappedStatement addMappedStatement(Class<?> mapperClass, String id, SqlSource sqlSource,SqlCommandType sqlCommandType, Class<?> parameterType,String resultMap, Class<?> resultType, KeyGenerator keyGenerator,String keyProperty, String keyColumn) {String statementName = mapperClass.getName() + DOT + id;if (hasMappedStatement(statementName)) {logger.warn(LEFT_SQ_BRACKET + statementName + "] Has been loaded by XML or SqlProvider or Mybatis's Annotation, so ignoring this injection for [" + getClass() + RIGHT_SQ_BRACKET);return null;}/* 缓存逻辑处理 */boolean isSelect = sqlCommandType == SqlCommandType.SELECT;return builderAssistant.addMappedStatement(id, sqlSource, StatementType.PREPARED, sqlCommandType,null, null, null, parameterType, resultMap, resultType,null, !isSelect, isSelect, false, keyGenerator, keyProperty, keyColumn,configuration.getDatabaseId(), languageDriver, null);}

这里会通过statementName(mapperClass.getName() + DOT + id)j检测是否存在,如果不存在则添加

org/apache/ibatis/builder/MapperBuilderAssistant.java

  public MappedStatement addMappedStatement(String id,SqlSource sqlSource,StatementType statementType,SqlCommandType sqlCommandType,Integer fetchSize,Integer timeout,String parameterMap,Class<?> parameterType,String resultMap,Class<?> resultType,ResultSetType resultSetType,boolean flushCache,boolean useCache,boolean resultOrdered,KeyGenerator keyGenerator,String keyProperty,String keyColumn,String databaseId,LanguageDriver lang,String resultSets) {if (unresolvedCacheRef) {throw new IncompleteElementException("Cache-ref not yet resolved");}id = applyCurrentNamespace(id, false);boolean isSelect = sqlCommandType == SqlCommandType.SELECT;MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType).resource(resource).fetchSize(fetchSize).timeout(timeout).statementType(statementType).keyGenerator(keyGenerator).keyProperty(keyProperty).keyColumn(keyColumn).databaseId(databaseId).lang(lang).resultOrdered(resultOrdered).resultSets(resultSets).resultMaps(getStatementResultMaps(resultMap, resultType, id)).resultSetType(resultSetType).flushCacheRequired(valueOrDefault(flushCache, !isSelect)).useCache(valueOrDefault(useCache, isSelect)).cache(currentCache);ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id);if (statementParameterMap != null) {statementBuilder.parameterMap(statementParameterMap);}MappedStatement statement = statementBuilder.build();configuration.addMappedStatement(statement);return statement;}public String applyCurrentNamespace(String base, boolean isReference) {if (base == null) {return null;}if (isReference) {// is it qualified with any namespace yet?if (base.contains(".")) {return base;}} else {// is it qualified with this namespace yet?if (base.startsWith(currentNamespace + ".")) {return base;}if (base.contains(".")) {throw new BuilderException("Dots are not allowed in element names, please remove it from " + base);}}return currentNamespace + "." + base;}

添加的话,最后的id会拼接上当前的namespace

小结

如果mybatis mapper定义了多个同名方法,则启动时不会报错,但是会有error日志告知同名方法被忽略。整体加载顺序是xml的方法优先于java mapper定义的方法,优先于自定义的SqlMethod;而xml或者java mapper方法都是以最先出现的为准。

相关文章:

聊聊mybatis-plus的sql加载顺序

序 本文主要研究一下如果mybatis mapper定义了多个同名方法会不会有问题 MybatisConfiguration com/baomidou/mybatisplus/core/MybatisConfiguration.java /*** MybatisPlus 加载 SQL 顺序&#xff1a;* <p> 1、加载 XML中的 SQL </p>* <p> 2、加载 SqlP…...

基于jeecg-boot的flowable流程审批时增加下一个审批人设置

更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; https://gitee.com/nbacheng/nbcio-boot 前端代码&#xff1a;https://gitee.com/nbacheng/nbcio-vue.git 在线演示&#xff08;包括H5&#xff09; &#xff1a; http://122.227.135.243:9888 因为有时…...

HTML 与 CSS 有什么区别?

HTML&#xff08;超文本标记语言&#xff09;和 CSS&#xff08;层叠样式表&#xff09;是构建网页的两个核心技术。HTML负责定义网页的结构和内容&#xff0c;而CSS则用于控制网页的样式和布局。虽然它们在构建网页时密切相关&#xff0c;但它们在功能和用途上有明显的区别。 …...

服务器数据恢复-vmware ESXI虚拟机数据恢复案例

服务器数据恢复环境&#xff1a; 从物理机迁移一台虚拟机到ESXI&#xff0c;迁移后做了一个快照。该虚拟机上部署了一个SQLServer数据库&#xff0c;存放了5年左右的数据。ESXI上有数十台虚拟机&#xff0c;EXSI连接了一台EVA存储&#xff0c;所有的虚拟机都在EVA存储上。 服务…...

Rabbitmq的Shovel

Federation 具备的数据转发功能类似&#xff0c; Shovel 够可靠、持续地从一个 Broker 中的队列 ( 作为源端&#xff0c;即source)拉取数据并转发至另一个 Broker 中的交换器 ( 作为目的端&#xff0c;即 destination) 。作为源端的队列和作为目的端的交换器可以同时位于…...

华为手机实用功能介绍

一、内置app介绍 分四块介绍&#xff0c;包括出门款、规划款、工作款和生活款。 出门款&#xff1a;红色框框部分&#xff0c;照镜子化妆/看天气 规划款&#xff1a;黄色框框部分&#xff0c;日程表/计划表/番茄时间/计时 工作款&#xff1a;蓝色框框部分&#xff0c;便笺/录…...

算法题打卡day50-动态规划 | 123.买卖股票的最佳时机III、188.买卖股票的最佳时机IV

123. 买卖股票的最佳时机 III - 力扣&#xff08;LeetCode&#xff09; 状态&#xff1a;查看索引含义和初始化思路后AC。 增加了两次的限制&#xff0c;相应的就是需要考虑的状态改变&#xff0c;具体的索引含义在代码中&#xff1a; class Solution { public:int maxProfit(…...

jvm与锁

今天是《面霸的自我修养》的第二弹&#xff0c;内容是Java并发编程中关于Java内存模型&#xff08;Java Memory Model&#xff09;和锁的基础理论相关的问题。这两块内容的八股文倒是不多&#xff0c;但是难度较大&#xff0c;接下来我们就一起一探究竟吧。 数据来源&#xff…...

零基础安装pycuda

零基础安装pycuda 前言安装Visual Studio安装C/C环境添加环境变量 安装pycuda查看系统位数查看python版本下载whl文件 前言 最近开始学习基于python的cuda编程&#xff0c;记录一下pycuda的安装。 在安装pycuda之前&#xff0c;首先需要有NVIDIA的独立显卡并且要安装CUDA和CUD…...

Streamlit 讲解专栏(十一):数据可视化-图表绘制详解(中)

文章目录 1 前言2 绘制交互式散点图3 定制图表主题4 增强数据可视化的交互性与注释步骤1步骤二 5 结语 1 前言 在上一篇博文《 Streamlit 讲解专栏&#xff08;十&#xff09;&#xff1a;数据可视化-图表绘制详解&#xff08;上&#xff09;》中&#xff0c;我们学习了一些关…...

d3dx9_35.dll丢失怎么解决

今天&#xff0c;我将为大家介绍关于电脑d3dx9_35.dll丢失的4种详细修复方法。希望通过这次分享&#xff0c;能够帮助大家解决在日常工作和生活中遇到的一些问题。 首先&#xff0c;让我们来了解一下d3dx9_35.dll是什么&#xff1f; d3dx9_35.dll是一个非常重要的动态链接库文…...

Ansible自动化运维工具(二)

目录 &#xff08;6&#xff09;copy模块 &#xff08;7&#xff09;file模块 ​编辑​编辑&#xff08;8&#xff09;hostname模块 &#xff08;9&#xff09;ping模块 &#xff08;10&#xff09;yum 模块 &#xff08;11&#xff09;service/system模块 ​编辑 ​…...

uniapp中使用原生canvas标签绘制视频帧来模拟拍照,拍照后将图绘制在另外一个canvas上编辑画图,这样反复操作

uniapp中使用原生canvas标签绘制视频帧来模拟拍照&#xff0c;拍照后将图绘制在另外一个canvas上编辑画图&#xff0c;这样反复操作会导致ios系统上白屏&#xff0c;canvas2d上下文为null,经查阅找到相关资料 IOS 创建Canvas过多导致getContext(‘2d’) 返回null 总 Canvas 内存…...

机器视觉工程师们,学习是工作以外的事情

面试时&#xff0c;领导问你&#xff0c;很多技术问题&#xff0c;你永远的回答是&#xff0c;我可以学。 公司以为你来公司的目标就是学习&#xff0c;学完就跑。 那你进公司的目标到底是什么&#xff1f; 我认为你&#xff0c;你最好想好再回答。 对于每一家公司来说&#xf…...

数据驱动的生活:探索未来七天生活指数API的应用

前言 随着科技的不断发展&#xff0c;数据已经成为我们生活中不可或缺的一部分。从社交媒体上的点赞和分享&#xff0c;到电子邮件和搜索引擎的历史记录&#xff0c;数据正在以前所未有的速度积累。而这些数据的利用不仅仅停留在社交媒体或商业领域&#xff0c;它们还可以为我…...

【数据分享】2006-2021年我国城市级别的集中供热相关指标(免费获取\20多项指标)

《中国城市建设统计年鉴》中细致地统计了我国城市市政公用设施建设与发展情况&#xff0c;在之前的文章中&#xff0c;我们分享过基于2006-2021年《中国城市建设统计年鉴》整理的2006—2021年我国城市级别的市政设施水平相关指标、2006-2021年我国城市级别的各类建设用地面积数…...

2022年研究生数学建模竞赛优秀论文汇总

A题&#xff1a;移动场景超分辨定位问题 参考代码论文1 论文2 论文3 论文4 论文5 论文6 论文7B题&#xff1a; 方形件排样优化与订单组批问题探析 参考代码论文1 论文2 论文3 论文4 论文5 论文6 论文7C题&#xff1a; 汽车制造涂装-总装缓存调序区调度优化问题论文1 论文2 论文…...

阿里云申请免费SSL证书的两种验证方式及配置服务器Tomcat升级HTTPS协议

通用教程&#xff0c;其他服务商的免费 SSL 证书也差不多是这个流程。&#xff08;至少腾讯云的操作步骤和本文是一致&#xff0c;嘻嘻&#xff01;&#xff09; 申请 SSL 证书 首先在阿里云上创建并申请 SSL 证书&#xff0c;之后选择 DNS 验证的方式&#xff0c;一种是手动配…...

SQL Server 和 MySql 语法和关键字的区别

SQL Server 和 MySql 语法和关键字的区别 ——用于SQLServer到MySql的转换 mysql的ifnull()函数对应sql的isnull()函数;mysql的存储过程中变量的定义去掉;mysql的每句结束要用";"SQLServer存储过程的AS在MySql中需要用begin .....end替换字符串连接用concat()函数;…...

2023_Spark_实验三:基于IDEA开发Scala例子

一、创建一个空项目&#xff0c;作为整个项目的基本框架 二、创建SparkStudy模块&#xff0c;用于学习基本的Spark基础 三、创建项目结构 1、在SparkStudy模块下的pom.xml文件中加入对应的依赖&#xff0c;并等待依赖包下载完毕。 在pom.xml文件中加入对应的依赖 ​<!-- S…...

2021-03-15 iview一些问题

1.iview 在使用tree组件时&#xff0c;发现没有set类的方法&#xff0c;只有get&#xff0c;那么要改变tree值&#xff0c;只能遍历treeData&#xff0c;递归修改treeData的checked&#xff0c;发现无法更改&#xff0c;原因在于check模式下&#xff0c;子元素的勾选状态跟父节…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

uniapp 开发ios, xcode 提交app store connect 和 testflight内测

uniapp 中配置 配置manifest 文档&#xff1a;manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号&#xff1a;4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...

适应性Java用于现代 API:REST、GraphQL 和事件驱动

在快速发展的软件开发领域&#xff0c;REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名&#xff0c;不断适应这些现代范式的需求。随着不断发展的生态系统&#xff0c;Java 在现代 API 方…...

uniapp 小程序 学习(一)

利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 &#xff1a;开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置&#xff0c;将微信开发者工具放入到Hbuilder中&#xff0c; 打开后出现 如下 bug 解…...

Qt的学习(一)

1.什么是Qt Qt特指用来进行桌面应用开发&#xff08;电脑上写的程序&#xff09;涉及到的一套技术Qt无法开发网页前端&#xff0c;也不能开发移动应用。 客户端开发的重要任务&#xff1a;编写和用户交互的界面。一般来说和用户交互的界面&#xff0c;有两种典型风格&…...

链式法则中 复合函数的推导路径 多变量“信息传递路径”

非常好&#xff0c;我们将之前关于偏导数链式法则中不能“约掉”偏导符号的问题&#xff0c;统一使用 二重复合函数&#xff1a; z f ( u ( x , y ) , v ( x , y ) ) \boxed{z f(u(x,y),\ v(x,y))} zf(u(x,y), v(x,y))​ 来全面说明。我们会展示其全微分形式&#xff08;偏导…...