MyBatis-Plus核心内容

MyBatis-Plus

MyBatis-Plus 是一个基于 MyBatis的增强工具,旨在简化开发过程,减少重复代码。它在MyBatis的基础上增加了CRUD操作封装,条件构造器、代码生成器等功能。

一、核心特性与优势

1. 核心特性
  • 无侵入:只做增强不做改变,完全兼容MyBatis
  • 自动CRUD:内置通用Mapper,单表操作无需编写sql
  • 条件构造器:通过Lambda表达式构建复杂查询条件
  • 代码生成器:自动生成Entity、Mapper、Service等代码
  • 分页插件:内置分页功能,支持多种数据库。
  • 乐观锁:内置乐观锁插件,防止脏数据更新。
  • 逻辑删除:支持逻辑删除,避免物理删除数据。
  • 多租户
2. 与原生 MyBatis 对比
功能原生 MyBatisMyBatis-Plus
单表 CRUD手动编写 XML 或注解内置通用 Mapper,零 SQL
条件查询手动拼接 SQL 或 XMLLambda 条件构造器
分页手动实现分页插件内置分页插件,一行代码搞定
代码生成需自定义模板内置代码生成器
性能分析需集成第三方插件内置性能分析插件

二、高级功能

1. 乐观锁插件
// 1. 配置乐观锁插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); // 乐观锁插件return interceptor;
}// 2. 实体类字段上添加 @Version 注解
@Data
public class Product {private Long id;private String name;@Versionprivate Integer version;
}// 3. 使用
Product product = productService.getById(1L);
product.setPrice(100);
productService.updateById(product); // 自动带上 version 条件
2. 逻辑删除
// 1. 配置逻辑删除插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new LogicSqlInjector()); // 逻辑删除插件return interceptor;
}// 2. 配置 application.yml
mybatis-plus:global-config:db-config:logic-not-delete-value: 0  # 未删除值(默认)logic-delete-value: 1      # 已删除值(默认)// 3. 实体类字段上添加 @TableLogic 注解
@Data
public class User {private Long id;private String name;@TableLogicprivate Integer deleted;
}// 4. 使用
userService.removeById(1L); // 实际执行 UPDATE user SET deleted=1 WHERE id=1 AND deleted=0
3. 性能分析插件
// 配置性能分析插件(开发环境使用)
@Bean
@Profile({"dev","test"}) // 设置 dev test 环境开启
public PerformanceInterceptor performanceInterceptor() {PerformanceInterceptor interceptor = new PerformanceInterceptor();interceptor.setMaxTime(100); // 最大执行时间,单位毫秒interceptor.setFormat(true); // SQL 是否格式化return interceptor;
}

三、整体架构与核心组件

1. 架构分层
┌───────────────────────────────────────────────────────────┐
│                          用户层                            │
│  (Service/Controller 通过 BaseMapper/IService 调用方法)   │
├───────────────────────────────────────────────────────────┤
│                         接口层                             │
│  (BaseMapper<T>, IService<T>, ServiceImpl<M extends      │
│   BaseMapper<T>, T>)                                       │
├───────────────────────────────────────────────────────────┤
│                         核心层                             │
│  (SqlRunner, SqlHelper, MybatisMapperMethod,              │
│   MybatisMapperProxy)                                      │
├───────────────────────────────────────────────────────────┤
│                        插件层                              │
│  (PaginationInnerInterceptor, OptimisticLockerInnerInterceptor,│
│   LogicSqlInjector)                                        │
├───────────────────────────────────────────────────────────┤
│                        配置层                              │
│  (MybatisPlusAutoConfiguration, MybatisPlusProperties)    │
├───────────────────────────────────────────────────────────┤
│                     MyBatis 原生层                          │
│  (SqlSession, Executor, StatementHandler, ResultSetHandler)│
└───────────────────────────────────────────────────────────┘
2. 核心组件
  • BaseMapper:提供基础 CRUD 方法的接口。
  • ServiceImpl:Service 层的默认实现,封装常用业务逻辑。
  • SqlHelper:SQL 执行工具类,与 MyBatis 交互。
  • MybatisMapperMethod:增强版 Mapper 方法调用处理器。
  • MybatisMapperProxy:Mapper 接口的代理实现。
  • InnerInterceptor:插件机制,用于分页、乐观锁等功能。
3.执行流程总结
用户调用 Service 方法
MP 代理对象拦截
构建 QueryWrapper/LambdaQueryWrapper
生成 SQL 条件
调用 MyBatis SqlSession
Executor 执行查询
插件拦截 分页,乐观锁等
StatementHandler 预处理 SQL
ParameterHandler 设置参数
执行 JDBC 查询
ResultSetHandler 映射结果集
返回结果给用户

四、自动配置原理

1. 自动配置入口
// MybatisPlusAutoConfiguration.java
@Configuration
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties(MybatisPlusProperties.class)
@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class})
public class MybatisPlusAutoConfiguration implements InitializingBean {@Bean@ConditionalOnMissingBeanpublic SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {// 创建 SqlSessionFactorySqlSessionFactoryBean factory = new SqlSessionFactoryBean();factory.setDataSource(dataSource);// 配置 MyBatis-Plus 专属设置Configuration configuration = new MybatisConfiguration();factory.setConfiguration(configuration);// 注册自定义类型处理器if (!ObjectUtils.isEmpty(this.properties.getTypeHandlersPackage())) {factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());}// 添加插件(分页、乐观锁等)if (!ObjectUtils.isEmpty(this.interceptors)) {factory.setPlugins(this.interceptors.toArray(new Interceptor[0]));}return factory.getObject();}// 其他 Bean 定义...
}
2. 插件注册流程
// MybatisPlusAutoConfiguration.java
@Bean
@ConditionalOnMissingBean
public MybatisPlusInterceptor mybatisPlusInterceptor() {return new MybatisPlusInterceptor();
}// 在需要使用插件的地方注入并配置
@Autowired
private MybatisPlusInterceptor interceptor;// 添加分页插件
@PostConstruct
public void addPageInterceptor() {interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
}

五、通用 CRUD 实现

1. BaseMapper 接口
public interface BaseMapper<T> extends Mapper<T> {int insert(T entity);int deleteById(Serializable id);int deleteByMap(@Param("cm") Map<String, Object> columnMap);int delete(@Param("ew") Wrapper<T> queryWrapper);int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);int updateById(@Param("et") T entity);int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);T selectById(Serializable id);List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);T selectOne(@Param("ew") Wrapper<T> queryWrapper);Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);Page<T> selectPage(Page<T> page, @Param("ew") Wrapper<T> queryWrapper);// 其他方法...
}
2. SQL 注入器(SqlInjector)

MP 通过 SqlInjector 将通用方法对应的 SQL 注入到 MyBatis 中:

// DefaultSqlInjector.java
public class DefaultSqlInjector extends AbstractSqlInjector {@Overridepublic List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {List<AbstractMethod> methodList = new ArrayList<>();// 添加基础 CRUD 方法methodList.add(new Insert());methodList.add(new Delete());methodList.add(new DeleteByMap());methodList.add(new DeleteById());methodList.add(new DeleteBatchIds());methodList.add(new Update());methodList.add(new UpdateById());methodList.add(new SelectById());methodList.add(new SelectBatchIds());methodList.add(new SelectByMap());methodList.add(new SelectOne());methodList.add(new SelectCount());methodList.add(new SelectList());methodList.add(new SelectPage());return methodList;}
}
3. 方法执行流程
// MybatisMapperMethod.java (关键方法)
public Object execute(SqlSession sqlSession, Object[] args) {Object result;// 根据方法类型执行不同逻辑switch (command.getType()) {case INSERT: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.insert(command.getName(), param));break;}case UPDATE: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.update(command.getName(), param));break;}case DELETE: {Object param = method.convertArgsToSqlCommandParam(args);result = rowCountResult(sqlSession.delete(command.getName(), param));break;}case SELECT:if (method.returnsVoid() && method.hasResultHandler()) {executeWithResultHandler(sqlSession, args);result = null;} else if (method.returnsMany()) {result = executeForMany(sqlSession, args);} else if (method.returnsMap()) {result = executeForMap(sqlSession, args);} else if (method.returnsCursor()) {result = executeForCursor(sqlSession, args);} else {Object param = method.convertArgsToSqlCommandParam(args);result = sqlSession.selectOne(command.getName(), param);if (method.returnsOptional() &&(result == null || !method.getReturnType().equals(result.getClass()))) {result = Optional.ofNullable(result);}}break;case FLUSH:result = sqlSession.flushStatements();break;default:throw new BindingException("Unknown execution method for: " + command.getName());}if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {throw new BindingException("Mapper method '" + command.getName() + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");}return result;
}

六、条件构造器(Wrapper)源码

1. 核心接口与类
// Wrapper 接口定义
public interface Wrapper<T> extends Serializable {String getSqlSegment();Object getEntity();Map<String, Object> getParamNameValuePairs();// 其他方法...
}// AbstractWrapper 实现基本逻辑
public abstract class AbstractWrapper<T, R, Children extends AbstractWrapper<T, R, Children>>implements Wrapper<T> {protected T entity;protected LinkedHashMap<String, Object> paramNameValuePairs = new LinkedHashMap<>();protected StringBuilder sqlWhere = new StringBuilder();// 条件方法实现public Children eq(R column, Object val) {return addCriterion("=", column, val);}public Children ne(R column, Object val) {return addCriterion("<>", column, val);}public Children gt(R column, Object val) {return addCriterion(">", column, val);}// 其他条件方法...
}// QueryWrapper 具体实现
public class QueryWrapper<T> extends AbstractWrapper<T, String, QueryWrapper<T>> {// 构造方法和特定方法
}// LambdaQueryWrapper 使用 Lambda 表达式
public class LambdaQueryWrapper<T> extends AbstractWrapper<T, SFunction<T, ?>, LambdaQueryWrapper<T>> {// Lambda 条件方法public <V> LambdaQueryWrapper<T> eq(SFunction<T, V> column, V val) {return super.eq(getColumn(column), val);}// 其他 Lambda 条件方法...
}
2. Lambda 表达式解析

MP 通过 com.baomidou.mybatisplus.core.toolkit.support.SFunctionLambdaUtils 解析 Lambda 表达式:

// LambdaUtils.java (关键方法)
public static <T> String getColumn(SFunction<T, ?> fn) {// 解析 Lambda 表达式获取字段名LambdaMeta meta = LambdaUtils.extract(fn);String fieldName = PropertyNamer.methodToProperty(meta.getImplMethodName());TableInfo tableInfo = TableInfoHelper.getTableInfo(meta.getInstantiatedType());// 根据字段名获取表列名if (tableInfo != null) {TableFieldInfo fieldInfo = tableInfo.getFieldList().stream().filter(f -> f.getProperty().equals(fieldName)).findFirst().orElse(null);if (fieldInfo != null) {return fieldInfo.getColumn();}}// 如果找不到,使用默认映射规则return StringUtils.camelToUnderline(fieldName);
}

七、分页插件实现

1. 核心拦截器
// PaginationInnerInterceptor.java
public class PaginationInnerInterceptor implements InnerInterceptor {@Overridepublic void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {// 获取分页参数IPage<?> page = findPage(parameter).orElse(null);if (page == null || page.getSize() < 0) {return;}// 获取数据库类型DbType dbType = this.dbType;if (dbType == null) {JdbcConnection connection = executor.getTransaction().getConnection();dbType = JdbcUtils.getDbType(connection.getMetaData().getURL());}// 根据不同数据库类型生成不同的分页 SQLDialect dialect = DialectFactory.getDialect(dbType);String buildSql = concatOrderBy(boundSql.getSql(), page);String pageSql = dialect.buildPaginationSql(buildSql, page.offset(), page.getSize());// 修改原始 SQLMetaObject metaObject = SystemMetaObject.forObject(boundSql);metaObject.setValue("sql", pageSql);}// 其他方法...
}
2. 方言实现
// MySQLDialect.java
public class MySQLDialect implements IDialect {@Overridepublic String buildPaginationSql(String originalSql, long offset, long limit) {StringBuilder sql = new StringBuilder(originalSql);sql.append(" LIMIT ").append(offset).append(",").append(limit);return sql.toString();}
}// OracleDialect.java
public class OracleDialect implements IDialect {@Overridepublic String buildPaginationSql(String originalSql, long offset, long limit) {StringBuilder sql = new StringBuilder();sql.append("SELECT * FROM (SELECT TMP.*, ROWNUM RN FROM (");sql.append(originalSql);sql.append(") TMP WHERE ROWNUM <= ").append(offset + limit);sql.append(") WHERE RN > ").append(offset);return sql.toString();}
}

八、面试题

1. 乐观锁和逻辑删除的实现原理是什么?
  • 乐观锁

    • 原理:通过版本号(@Version 注解)实现,更新时检查版本号是否一致。
    • 流程:查询时获取版本号 → 更新时带上版本号条件 → 成功后版本号 + 1。
  • 逻辑删除

    • 原理:通过 @TableLogic 注解标记字段,将 DELETE 转换为 UPDATE。
    • 配置:设置 logic-not-delete-value=0logic-delete-value=1
2. 如何自定义 MyBatis-Plus 的插件?
  1. 实现 InnerInterceptor 接口。
  2. 重写 beforeQuerybeforeUpdate 等方法,在 SQL 执行前后进行拦截。
  3. 将插件注册到 MybatisPlusInterceptor 中。
3. MyBatis 的核心组件有哪些?各自的职责是什么?
  • SqlSessionFactory:创建 SqlSession 的工厂,通过 SqlSessionFactoryBuilder 构建。
  • SqlSession:数据库操作的核心接口,提供执行 SQL 的方法。
  • Executor:SQL 执行器,负责处理缓存、事务和 SQL 执行。
  • StatementHandler:处理 SQL 语句的预编译和参数设置。
  • ParameterHandler:处理 SQL 参数。
  • ResultSetHandler:处理查询结果集,映射到 Java 对象。
4. MyBatis 中 #{} 和 ${} 的区别是什么?
  • #{}:预编译处理,将参数替换为占位符 ?,调用PreparedStatement 的set 方法来赋值,防止 SQL 注入。

  • ${}:字符串替换,直接将参数插入 SQL,存在 SQL 注入风险。

  • 示例

    // #{} 生成:SELECT * FROM user WHERE name = ?
    @Select("SELECT * FROM user WHERE name = #{name}")// ${} 生成:SELECT * FROM user WHERE name = '张三'
    @Select("SELECT * FROM user WHERE name = '${name}'")
    
5. MyBatis 的缓存机制是怎样的?
  • 一级缓存

    :基于SqlSessionSqlSession的本地缓存,默认开启。

    • 生命周期:与 SqlSession 一致,Session 关闭时缓存清空。
  • 二级缓存

    :全局缓存,基于namespace隔离。

    • 配置方式:在映射文件中添加 标签或使用 @CacheNamespace 注解。
  • 流程:查询时优先从二级缓存获取 → 再从一级缓存获取 → 最后查询数据库。

6. 如何配置 MyBatis 的二级缓存?

(1) MyBatis 的缓存分为一级缓存和 二级缓存。

一级缓存是 SqlSession 级别的缓存,默认开启。

二级缓存是 NameSpace 级别(Mapper)的缓存,多个 SqlSession 可以共享,使用时需要进行配置开启。

(2) 缓存的查找顺序:二级缓存 => 一级缓存 => 数据库

  1. mybatis-config.xml中启用二级缓存:

    <settings><setting name="cacheEnabled" value="true"/>
    </settings>
    
  2. 在映射文件中配置缓存:

    <cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
    
  3. 实体类实现 Serializable 接口。

7. MyBatis 的插件机制是如何工作的?

参考答案

  • 基于 责任链模式动态代理
  • 插件可以拦截 ExecutorStatementHandlerParameterHandlerResultSetHandler 的方法。
  • 自定义插件需实现 Interceptor 接口,使用 @Intercepts@Signature 注解指定拦截点。
8.MyBatis如何获取自动生成的(主)键值

在标签中使用 useGeneratedKeys 和 keyProperty 两个属性来获取自动生成的主键值。

<insert id=”insertname” usegeneratedkeys=”true” keyproperty=”id”>
insert into names (name) values (#{name})
</insert>
9.简述Mybatis的动态SQL,列出常用的6个标签及作用
  • Mybatis 动态sql可以让我们在xml映射文件中,以标签的形式编写动态sql,完成逻辑判断和动态拼接sql的功能。

  • Mybatis 提供了9中动态sql标签:

    : 进行条件的判断

    :在判断后的 SQL 语句前面添加 WHERE 关键字,并处理 SQL 语句开始位置的 AND 或者 OR 的问题

    :可以在 SQL 语句前后进行添加指定字符 或者去掉指定字符.

    : 主要用于修改操作时出现的逗号问题

    :类似于 java 中的 switch 语句.在所有的条件中选择其一

    :迭代操作

  • 其执行原理:使用OGNL 从sql参数对象中计算表达式的值,更具表达式的值动态拼接sql,以此来完成动态sql功能

10.Mybatis 的 Xml 映射文件中,不同的 Xml 映射文件,id 是否可以重复?

不同的 Xml 映射文件,如果配置了 namespace,那么 id 可以重复;如果没有配置namespace,那么 id 不能重复;毕竟 namespace 不是必须的,只是最佳实践而已。原因就是 namespace+id 是作为 Map<String, MappedStatement>的 key 使用的,如果没有namespace,就剩下 id,那么,id 重复会导致数据互相覆盖。有了 namespace,自然 id 就可以重复,namespace 不同,namespace+id 自然也就不同。

11.Mybatis 都有哪些 Executor 执行器?它们之间的区别是什么?

Mybatis 有三种基本的 Executor 执行器,SimpleExecutor、ReuseExecutor、BatchExecutor。

1)SimpleExecutor:每执行一次 update 或 select,就开启一个 Statement 对象,用完立刻关闭 Statement 对象。

2)ReuseExecutor:执行 update 或 select,以 sql 作为
key 查找 Statement 对象,存在就使用,不存在就创建,用完后,不关闭 Statement 对象,而是放置于 Map

3)BatchExecutor:完成批处理。

12.Mybatis 中如何指定使用哪一种 Executor 执行器?

在 Mybatis 配置文件中,可以指定默认的 ExecutorType 执行器类型,也可以手动给DefaultSqlSessionFactory 的创建 SqlSession 的方法传递 ExecutorType 类型参数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/93177.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/93177.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络摘星题库800题笔记 第4章 网络层

第4章 网络层4.1 网络层概述题组闯关1.在 Windows 的网络配置中&#xff0c;“默认网关” 一般被设置为 ( ) 的地址。 A. DNS 服务器 B. Web 服务器 C. 路由器 D. 交换机1.【参考答案】C 【解析】只有在计算机上正确安装网卡驱动程序和网络协议&#xff0c;并正确设置 IP 地址信…

非root用户在linux中配置zsh(已解决ncurses-devel报错)

Zsh&#xff08;Z Shell&#xff09;是一款功能强大的交互式 Unix shell&#xff0c;以其高度可定制性和丰富的功能著称&#xff0c;被视为 Bash 的增强替代品。它支持智能补全、主题美化、插件扩展&#xff08;如 Oh My Zsh 框架&#xff09;、自动纠错、全局别名等特性&#…

《Foundations and Recent Trends in Multimodal Mobile Agents: A Survey》论文精读笔记

论文链接&#xff1a;https://arxiv.org/pdf/2411.02006 摘要 文章首先介绍了核心组件&#xff0c;并探讨了移动基准和交互环境中的关键代表性作品&#xff0c;旨在全面理解研究重点及其局限性。 接着&#xff0c;将这些进展分为两种主要方法&#xff1a; 基于提示的方法&a…

npm安装时一直卡住的解决方法

npm install 卡住通常是由于网络问题或缓存问题导致的。以下是几种解决方法&#xff1a; 方法1&#xff1a;清理npm缓存 npm cache clean --force npm install方法2&#xff1a;删除node_modules和package-lock.json重新安装 rm -rf node_modules package-lock.json npm instal…

[密码学实战]使用Java生成国密SM2加密证书等(四十三)

[密码学实战]使用Java生成国密SM2加密证书等(四十三) 本文将详细介绍如何通过Java代码生成符合国密标准的SM2加密证书,包括密钥对生成、证书扩展属性配置、PEM格式保存等关键步骤。 一. 运行结果示例 二. 国密算法与加密证书 国密算法(SM系列)是中国自主研发的密码算法体…

从零开始之stm32之CAN通信

从小白的视角了解并实现简单的STM32F103的CAN通信&#xff0c;直接上手。一、CAN协议简介CAN总线上传输的信息称为报文&#xff0c;当总线空闲时任何连接的单元都可以开始发送新的报文&#xff0c;有5种类型的帧&#xff1a;数据帧、遥控帧、错误帧、过载帧、帧间隔。数据帧有两…

Java 课程,每天解读一个简单Java之利用条件运算符的嵌套来完成此题:学习成绩>=90分的同学用A表示,60-89分之间的用B表示, * 60分以下

package ytr250812;/*题目&#xff1a;利用条件运算符的嵌套来完成此题&#xff1a;学习成绩>90分的同学用A表示&#xff0c;60-89分之间的用B表示&#xff0c;* 60分以下*/import java.util.Scanner;public class GradeEvaluator {public static void main(String[] args) …

Word XML 批注范围克隆处理器

该类用于处理 Word 文档&#xff08;XML 结构&#xff09;中被批注标记的文本范围&#xff0c; 实现指定内容的深度克隆&#xff0c;并将其插入到目标节点之后。 适用于在生成或修改 .docx 文件时复制批注内容块。/*** Word XML 批注范围克隆处理器* * 该类用于处理 Word 文档&…

MQTT:Java集成MQTT

目录Git项目路径一、原生java架构1.1 导入POM文件1.2 编写测试用例二、SpringBoot集成MQTT2.1 导入POM文件2.2 在YML文件中增加配置2.3 新建Properties配置文件映射配置2.4 创建连接工厂2.5 增加入站规则配置2.6 增加出站规则配置2.7 创建消息发送网关2.8 测试消息发送2.9 项目…

day 16 stm32 IIC

1.IIC概述1基于对话的形式完成&#xff0c;不需要同时进行发送和接收所以删掉了一根数据线&#xff0c;变成半双工2为了安全起见添加了应答机制3可以接多个模块&#xff0c;且互不干扰4异步时序&#xff0c;要求严格&#xff0c;发送过程中不能暂停&#xff0c;所以需要同步时序…

AMD KFD的BO设计分析系列 0:开篇

开启我始终不敢碰的GPU存储系列&#xff0c;先上个图把核心关系表达下&#xff0c;以此纪念。注&#xff1a;图中kfdm_mm误写&#xff0c;应该为kfd_mm&#xff0c;不修改了&#xff0c;请大家不要介意。

EUDR的核心内容,EUDR认证的好处,EUDR意义

近年来&#xff0c;全球森林退化问题日益严峻&#xff0c;毁林行为不仅加剧气候变化&#xff0c;还威胁生物多样性和原住民权益。为应对这一挑战&#xff0c;欧盟于2023年6月正式实施《欧盟零毁林法案》&#xff08;EU Deforestation-free Regulation, EUDR&#xff09;&#x…

数据分析专栏记录之 -基础数学与统计知识

数据分析专栏记录之 -基础数学与统计知识&#xff1a; 1、描述性统计 均值 data_set [10, 20, 30, 40, 50] mean sum(data_set)/len(data_set)np 里面的函数&#xff0c;对二维进行操作时&#xff0c; 默认每一列 mean1 np.mean(data_set) print(mean, mean1)s 0 for i…

《星辰建造师:C++多重继承的奇幻史诗》

&#x1f30c;&#x1f525; 《星辰建造师&#xff1a;多重继承与this指针的终极史诗》 &#x1f525;&#x1f30c;—— 一场融合魔法、科技与哲学的C奇幻冒险&#x1f320;&#x1f30c; 序章&#xff1a;代码宇宙的诞生 &#x1f30c;&#x1f320;在无尽的代码维度中&#…

云计算-OpenStack 运维开发实战:从 Restful API 到 Python SDK 全场景实现镜像上传、用户创建、云主机部署全流程

一、python-Restful Api 简介 Restful API 是一种软件架构风格,基于 HTTP 协议设计,通过统一的接口(如 URL 路径)和标准的 HTTP 方法(GET/POST/PUT/DELETE 等)实现资源(如数据、文件等)的操作,具有无状态、可缓存、客户端 - 服务器分离等特点。方法如下 用 GET 请求获…

RxJava 在 Android 中的深入解析:使用、原理与最佳实践

前言RxJava 是一个基于观察者模式的响应式编程库&#xff0c;它通过可观察序列和函数式操作符的组合&#xff0c;简化了异步和事件驱动程序的开发。在 Android 开发中&#xff0c;RxJava 因其强大的异步处理能力和简洁的代码风格而广受欢迎。本文将深入探讨 RxJava 的使用、核心…

面试实战 问题三十 HTTP协议中TCP三次握手与四次挥手详解

HTTP协议中TCP三次握手与四次挥手详解 在HTTP协议中&#xff0c;连接建立和断开依赖于底层的TCP协议。虽然HTTP本身不定义握手过程&#xff0c;但所有HTTP通信都通过TCP三次握手建立连接&#xff0c;通过四次挥手断开连接。以下是详细解析&#xff1a;一、TCP三次握手&#xff…

读《精益数据分析》:双边市场的核心指标分析

双边市场数据分析指南&#xff1a;从指标体系到实战落地&#xff08;基于《精益数据分析》框架&#xff09;在互联网平台经济中&#xff0c;双边市场&#xff08;如电商、出行、外卖、自由职业平台等&#xff09;的核心矛盾始终是"供需平衡与效率优化"。这类平台连接…

Queue参考代码

queue.c #include "queue.h" #include "stdlib.h" // 初始化循环队列 void initializeCircularQueue(CircularQueue *cq, uint8_t *buffer, uint32_t size) {cq->front 0;cq->rear 0;cq->count 0;cq->size size;cq->data buffer; }…

通过时间计算地固系到惯性系旋转矩阵

通过时间计算地固系到惯性系旋转矩阵 1. 引言 在航天工程和卫星导航领域&#xff0c;经常需要在地固坐标系(ECEF)和惯性坐标系(ECI)之间进行转换。本文将详细介绍如何根据UTC时间计算这两个坐标系之间的旋转矩阵&#xff0c;并提供完整的C语言实现。 2. 基本概念 2.1 坐标系定义…