MyBatis-Plus深度全解:从入门到企业级实战

MyBatis-Plus深度全解:从入门到企业级实战

一、为什么选择MyBatis-Plus?

1.1 MyBatis的痛点

- 重复CRUD代码编写
- 分页功能实现复杂
- 缺少通用Service层封装
- 动态表名支持困难
- 多租户方案需自行实现

1.2 MyBatis-Plus核心优势

+ 无侵入:只做增强不做改变
+ 强大的CRUD操作:内置通用Mapper/Service
+ 支持Lambda形式调用
+ 主键自动生成策略
+ 全局拦截器(分页/租户/性能分析)

1.3 技术栈对比

特性MyBatisMyBatis-PlusJPA
CRUD简化手动自动生成自动
分页插件需集成内置内置
代码生成器强大中等
多租户支持手动注解配置需扩展
学习曲线中等平滑陡峭

二、SpringBoot 3.x整合实战

2.1 环境准备

技术栈版本说明
SpringBoot3.1.0基础框架
Java17LTS版本
MySQL8.0数据库
MyBatis-Plus3.5.3.1ORM框架

2.2 依赖引入

<dependencies><!-- SpringBoot基础 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- MyBatis-Plus核心 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.3.1</version></dependency><!-- 数据库驱动 --><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><!-- Lombok简化开发 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>
</dependencies>

2.3 配置文件

spring:datasource:url: jdbc:mysql://localhost:3306/mp_demo?useSSL=false&serverTimezone=Asia/Shanghaiusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driver# MyBatis-Plus配置
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 开启SQL日志map-underscore-to-camel-case: true # 下划线转驼峰global-config:db-config:id-type: assign_id # 雪花算法ID生成logic-delete-field: deleted # 逻辑删除字段logic-delete-value: 1 # 已删除值logic-not-delete-value: 0 # 未删除值

2.4 实体类与Mapper

@Data
@TableName("sys_user") // 表名映射
public class User {@TableId(type = IdType.ASSIGN_ID) // 雪花算法IDprivate Long id;@TableField("username") // 字段映射private String name;private Integer age;private String email;@TableField(fill = FieldFill.INSERT) // 自动填充private LocalDateTime createTime;@TableField(fill = FieldFill.INSERT_UPDATE)private LocalDateTime updateTime;
}// Mapper接口
@Mapper
public interface UserMapper extends BaseMapper<User> {// 自定义方法@Select("SELECT * FROM sys_user WHERE age > #{age}")List<User> selectUsersByAge(@Param("age") Integer age);
}

三、核心功能深度解析

3.1 CRUD接口详解

3.1.1 Mapper层CRUD
// 插入
User user = new User();
user.setName("John");
user.setAge(30);
userMapper.insert(user); // 批量插入
List<User> users = Arrays.asList(new User(...), new User(...));
userMapper.insertBatchSomeColumn(users); // 批处理优化// 更新
User updateUser = new User();
updateUser.setId(1L);
updateUser.setEmail("new@example.com");
userMapper.updateById(updateUser);// 条件更新
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
wrapper.set("email", "admin@example.com").eq("name", "admin");
userMapper.update(null, wrapper);// 删除
userMapper.deleteById(1L); // ID删除
userMapper.delete(new QueryWrapper<User>().eq("age", 18)); // 条件删除
3.1.2 Service层CRUD
public interface UserService extends IService<User> {// 自定义业务方法List<User> findAdmins();
}@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {@Overridepublic List<User> findAdmins() {LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();wrapper.eq(User::getRole, "admin");return baseMapper.selectList(wrapper);}
}// 使用示例
userService.save(user); // 保存
userService.updateById(user); // 更新
userService.removeByIds(Arrays.asList(1L,2L)); // 批量删除

3.2 条件构造器(Wrapper)

3.2.1 QueryWrapper
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.select("id", "name", "age") // 指定字段.like("name", "张")          // 模糊查询.between("age", 20, 30)     // 范围查询.isNotNull("email")          // 非空判断.orderByDesc("create_time"); // 排序
List<User> users = userMapper.selectList(wrapper);
3.2.2 LambdaQueryWrapper(推荐)
LambdaQueryWrapper<User> lambdaWrapper = new LambdaQueryWrapper<>();
lambdaWrapper.select(User::getId, User::getName, User::getAge).like(User::getName, "张").ge(User::getAge, 18).orderByDesc(User::getCreateTime);
List<User> users = userMapper.selectList(lambdaWrapper);
3.2.3 复杂条件示例
LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();
wrapper.and(wq -> wq.gt(User::getAge, 18).or().isNull(User::getEmail)).nested(nq -> nq.eq(User::getRole, "admin").lt(User::getCreateTime, LocalDateTime.now())).apply("date_format(create_time,'%Y-%m-%d') = {0}", "2023-07-01");

3.3 分页插件(企业级优化)

@Configuration
public class MybatisPlusConfig {/*** 分页插件 + 性能分析插件*/@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 分页插件(MySQL方言)PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);paginationInterceptor.setMaxLimit(1000L); // 单页最大1000条paginationInterceptor.setOverflow(true);   // 超过总页数返回第一页interceptor.addInnerInterceptor(paginationInterceptor);// 性能分析插件(仅开发环境)if (log.isDebugEnabled()) {PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();performanceInterceptor.setFormat(true);performanceInterceptor.setMaxTime(2000); // SQL执行超过2秒记录警告interceptor.addInnerInterceptor(performanceInterceptor);}return interceptor;}
}// 使用示例
Page<User> page = new Page<>(1, 10); // 第1页,每页10条
LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();
wrapper.eq(User::getRole, "admin");
Page<User> result = userMapper.selectPage(page, wrapper);// 结果处理
List<User> records = result.getRecords();
long total = result.getTotal();

四、高级特性实战

4.1 逻辑删除

# 全局配置
mybatis-plus:global-config:db-config:logic-delete-field: deleted  # 逻辑删除字段名logic-delete-value: 1        # 删除值logic-not-delete-value: 0    # 未删除值

4.2 自动填充

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {@Overridepublic void insertFill(MetaObject metaObject) {this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());}@Overridepublic void updateFill(MetaObject metaObject) {this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());}
}

4.3 多租户方案

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 多租户插件TenantLineInnerInterceptor tenantInterceptor = new TenantLineInnerInterceptor();tenantInterceptor.setTenantLineHandler(new TenantLineHandler() {@Overridepublic Expression getTenantId() {// 从安全上下文获取租户IDreturn new LongValue(SecurityUtils.getTenantId());}@Overridepublic String getTenantIdColumn() {return "tenant_id";}@Overridepublic boolean ignoreTable(String tableName) {// 忽略系统表return "sys_config".equals(tableName);}});interceptor.addInnerInterceptor(tenantInterceptor);return interceptor;
}

4.4 枚举处理

// 枚举定义
@Getter
public enum UserStatus {ENABLED(1, "启用"),DISABLED(0, "禁用");@EnumValue // 标记数据库存储值private final int code;private final String desc;UserStatus(int code, String desc) {this.code = code;this.desc = desc;}
}// 实体类字段
private UserStatus status;

4.5 动态表名

public class DynamicTableNameParser implements TableNameHandler {private ThreadLocal<String> tableName = new ThreadLocal<>();public void setTableName(String tableName) {this.tableName.set(tableName);}@Overridepublic String dynamicTableName(String sql, String tableName) {return this.tableName.get() != null ? this.tableName.get() : tableName;}
}// 使用示例
DynamicTableNameParser parser = new DynamicTableNameParser();
parser.setTableName("user_2023"); // 设置动态表名TableNameHelper.setTableNameParser(parser);
List<User> users = userMapper.selectList(null); // 操作user_2023表

五、代码生成器(企业级配置)

5.1 生成器配置

public class CodeGenerator {public static void main(String[] args) {AutoGenerator generator = new AutoGenerator();// 全局配置GlobalConfig globalConfig = new GlobalConfig();globalConfig.setOutputDir(System.getProperty("user.dir") + "/src/main/java");globalConfig.setAuthor("YourName");globalConfig.setOpen(false);globalConfig.setSwagger2(true); // 开启Swagger注解generator.setGlobalConfig(globalConfig);// 数据源配置DataSourceConfig dataSourceConfig = new DataSourceConfig();dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/mp_demo");dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");dataSourceConfig.setUsername("root");dataSourceConfig.setPassword("123456");generator.setDataSource(dataSourceConfig);// 包配置PackageConfig packageConfig = new PackageConfig();packageConfig.setParent("com.example.mp");packageConfig.setEntity("entity");packageConfig.setMapper("mapper");packageConfig.setService("service");packageConfig.setController("controller");generator.setPackageInfo(packageConfig);// 策略配置StrategyConfig strategy = new StrategyConfig();strategy.setNaming(NamingStrategy.underline_to_camel);strategy.setColumnNaming(NamingStrategy.underline_to_camel);strategy.setEntityLombokModel(true); // 使用Lombokstrategy.setRestControllerStyle(true); // RESTful风格strategy.setInclude("sys_user", "sys_role"); // 生成表// 自定义模板TemplateConfig templateConfig = new TemplateConfig();templateConfig.setController("templates/controller.java");templateConfig.setService("templates/service.java");templateConfig.setServiceImpl("templates/serviceImpl.java");generator.setTemplate(templateConfig);generator.execute();}
}

5.2 自定义模板示例

// templates/controller.java.vm
package ${package.Controller};@RestController
@RequestMapping("/${table.entityPath}")
@RequiredArgsConstructor
public class ${table.controllerName} {private final ${table.serviceName} ${table.entityPath}Service;@GetMapping("/{id}")public Result<${entity}> getById(@PathVariable ${table.keyType} id) {return Result.success(${table.entityPath}Service.getById(id));}// 其他方法...
}

六、性能优化指南

6.1 SQL执行效率优化

// 1. 启用批处理
@Bean
public ConfigurationCustomizer configurationCustomizer() {return configuration -> {configuration.setDefaultExecutorType(ExecutorType.BATCH); // 批处理模式};
}// 2. 使用流式查询
try (Cursor<User> cursor = userMapper.selectCursor(queryWrapper)) {cursor.forEach(user -> process(user));
}// 3. 禁用XML热加载(生产环境)
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl # 关闭日志local-cache-scope: statement # 减小缓存范围

6.2 查询优化技巧

// 1. 只查询必要字段
LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();
wrapper.select(User::getId, User::getName);// 2. 避免N+1查询(关联查询优化)
@Select("SELECT u.*, d.name AS dept_name FROM user u LEFT JOIN dept d ON u.dept_id = d.id")
List<UserVO> selectUserWithDept();// 3. 使用二级缓存
@CacheNamespace(implementation = MybatisRedisCache.class, eviction = MybatisRedisCache.class)
public interface UserMapper extends BaseMapper<User> {
}

6.3 索引优化建议

-- 联合索引示例
CREATE INDEX idx_user_age_role ON sys_user(age, role);-- 覆盖索引查询
EXPLAIN SELECT id, name FROM sys_user WHERE age BETWEEN 20 AND 30;

七、企业级实战案例

7.1 数据权限控制

public class DataPermissionInterceptor implements InnerInterceptor {@Overridepublic void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {// 获取当前用户数据权限DataScope dataScope = SecurityUtils.getDataScope();if (dataScope != null) {// 修改SQL添加权限过滤String sql = boundSql.getSql();String newSql = sql + " AND " + dataScope.getSqlSegment();// 反射修改BoundSQLField field = boundSql.getClass().getDeclaredField("sql");field.setAccessible(true);field.set(boundSql, newSql);}}
}// 注册拦截器
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();interceptor.addInnerInterceptor(new DataPermissionInterceptor());return interceptor;
}

7.2 多数据源动态切换

// 1. 配置多数据源
@Configuration
public class DataSourceConfig {@Bean@ConfigurationProperties("spring.datasource.master")public DataSource masterDataSource() {return DruidDataSourceBuilder.create().build();}@Bean@ConfigurationProperties("spring.datasource.slave")public DataSource slaveDataSource() {return DruidDataSourceBuilder.create().build();}@Beanpublic DataSource dynamicDataSource() {Map<Object, Object> dataSourceMap = new HashMap<>();dataSourceMap.put("master", masterDataSource());dataSourceMap.put("slave", slaveDataSource());DynamicDataSource dataSource = new DynamicDataSource();dataSource.setDefaultTargetDataSource(masterDataSource());dataSource.setTargetDataSources(dataSourceMap);return dataSource;}
}// 2. 数据源切换注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DS {String value() default "master";
}// 3. 切面实现
@Aspect
@Component
public class DataSourceAspect {@Around("@annotation(ds)")public Object around(ProceedingJoinPoint point, DS ds) throws Throwable {String dsKey = ds.value();DynamicDataSourceContextHolder.push(dsKey);try {return point.proceed();} finally {DynamicDataSourceContextHolder.poll();}}
}// 4. 使用示例
@Service
public class UserService {@DS("slave") // 从库查询public User getById(Long id) {return userMapper.selectById(id);}@DS("master") // 主库写入public void saveUser(User user) {userMapper.insert(user);}
}

八、源码解析(核心设计思想)

8.1 SQL注入器原理

// 核心流程
AbstractSqlInjector#inspectInject() -> 解析Mapper接口方法-> 根据方法名匹配内置方法(selectById等)-> 构造对应的SqlMethod-> 创建MappedStatement// 自定义注入示例
public class MySqlInjector extends DefaultSqlInjector {@Overridepublic List<AbstractMethod> getMethodList(Class<?> mapperClass) {List<AbstractMethod> methods = super.getMethodList(mapperClass);methods.add(new FindAll()); // 添加自定义方法return methods;}
}// 自定义方法实现
public class FindAll extends AbstractMethod {@Overridepublic MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {String sql = "SELECT * FROM %s";String formattedSql = String.format(sql, tableInfo.getTableName());SqlSource sqlSource = languageDriver.createSqlSource(configuration, formattedSql, modelClass);return this.addSelectMappedStatementForTable(mapperClass, "findAll", sqlSource, tableInfo);}
}

8.2 条件构造器原理

// 核心:AbstractWrapper
public abstract class AbstractWrapper<T, R, Children> implements Compare<Children, R>, Nested<Children, Children> {// 存储条件表达式protected List<SqlSegment> expression = new ArrayList<>();// 条件构建示例public Children eq(boolean condition, R column, Object val) {if (condition) {expression.add(new SimpleSqlSegment(() -> columnToString(column), () -> " = ", () -> formatSqlValue(val)));}return typedThis;}
}// SQL片段生成
public String getSqlSegment() {return expression.stream().map(SqlSegment::getSqlSegment).filter(Objects::nonNull).collect(Collectors.joining(" "));
}

九、常见问题排查

9.1 字段映射问题

问题现象:实体类字段与数据库列不匹配
解决方案

// 1. 明确指定映射
@TableField(value = "db_column")// 2. 关闭自动驼峰转换
mybatis-plus:configuration:map-underscore-to-camel-case: false// 3. 检查字段类型是否匹配

9.2 分页失效问题

问题现象:分页查询返回所有结果
排查步骤

  1. 检查是否配置分页插件
  2. 确认Page对象作为第一个参数
  3. 验证SQL是否支持分页(无order by可能导致分页异常)

9.3 逻辑删除不生效

解决方案

# 1. 确认全局配置
mybatis-plus:global-config:db-config:logic-delete-field: deleted# 2. 实体类添加注解
@TableLogic
private Integer deleted;

9.4 多租户SQL异常

典型错误:INSERT语句缺少租户ID
解决方案

// 在TenantLineHandler中实现租户ID获取
@Override
public Expression getTenantId() {return new LongValue(SecurityUtils.getTenantId());
}// 确保INSERT操作包含租户字段

十、未来展望(MyBatis-Plus 4.0)

10.1 新特性预览

  • 响应式编程支持:整合Project Reactor
  • GraalVM原生镜像:提升启动速度
  • 增强的多租户方案:支持更复杂的租户隔离
  • 分布式ID生成器:内置更多分布式ID方案

10.2 架构演进

MyBatis Core
MyBatis-Plus 3.x
扩展接口
SQL注入器
元数据处理
拦截器链
4.0插件体系

结语

MyBatis-Plus作为MyBatis的增强工具,在企业级应用开发中展现出强大价值。本文涵盖了从基础配置到高级特性的全链路实践,重点包含:

  1. 核心功能深度解析:条件构造器、分页插件、代码生成器
  2. 企业级方案:多租户、数据权限、动态数据源
  3. 性能优化:批处理、流式查询、索引优化
  4. 源码级原理:SQL注入器、条件构造器实现
  5. 生产环境问题排查

最佳实践建议

  • 复杂查询仍推荐XML方式
  • 生产环境关闭SQL日志
  • 使用LambdaQueryWrapper避免字段魔法值
  • 定期进行SQL性能分析

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

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

相关文章

【无标题】路径着色问题的革命性重构:拓扑色动力学模型下的超越与升华

路径着色问题的革命性重构&#xff1a;拓扑色动力学模型下的超越与升华 一、以色列路径着色模型的根本局限 mermaid graph TB A[以色列路径着色模型] --> B[强连通约束] A --> C[仅实边三角剖分] A --> D[静态色彩分配] B --> E[无法描述非相邻关系] C --> F[忽…

01 Deep learning神经网络的编程基础 二分类--吴恩达

二分类 1. 核心定义 二分类任务是监督学习中最基础的问题类型&#xff0c;其目标是将样本划分为两个互斥类别。设样本特征空间为 X ⊆ R n \mathcal{X} \subseteq \mathbb{R}^n X⊆Rn&#xff0c;输出空间为 Y { 0 , 1 } \mathcal{Y} \{0,1\} Y{0,1}&#xff0c;学习目标为…

数据结构:递归:泰勒展开式(Taylor Series Expansion)

目录 第一步&#xff1a;❓我们要解决什么&#xff1f; 第二步&#xff1a;将其类比为求自然数和 第三步&#xff1a;什么是每一项&#xff1f; 第四步&#xff1a;定义要计算的每一项&#xff08;term&#xff09; 第五步&#xff1a;定义递归函数结构 &#x1f333; 调用…

Hadolint:Dockerfile 语法检查与最佳实践验证的终极工具

在容器化应用开发的浪潮中,Dockerfile 作为构建 Docker 镜像的核心配置文件,其质量直接影响着应用的安全性、稳定性和可维护性。然而,随着项目复杂度的增加,手动检查 Dockerfile 不仅耗时,还容易遗漏潜在问题。今天,我要向大家介绍一款强大的工具——Hadolint,它将彻底改…

redis数据过期策略、淘汰策略

过期键的删除策略​ ​​1. 被动删除&#xff08;惰性删除&#xff09;​​ ​​触发时机​​&#xff1a;当客户端尝试访问某个键时&#xff0c;Redis会先检查该键是否过期。就是说&#xff0c;我们不时时检查每个键是否过期&#xff0c;而是在使用到这个键时检查是否过期&a…

ES 学习总结一 基础内容

ElasticSearch学习 一、 初识ES1、 认识与安装2、 倒排索引2.1 正向索引2.2 倒排索引 3、 基本概念3.1 文档和字段3.2 索引和倒排 4 、 IK分词器 二、 操作1、 mapping 映射属性2、 索引库增删改查3、 文档的增删改查3.1 新增文档3.2 查询文档3.3 删除文档3.4 修改文档3.5 批处…

鸿蒙任务项设置案例实战

目录 案例效果 资源文件与初始化 string.json color.json CommonConstant 添加任务 首页组件 任务列表初始化 任务列表视图 任务编辑页 添加跳转 任务目标设置模型&#xff08;formatParams&#xff09; 编辑页面 详情页 任务编辑列表项 目标设置展示 引入目标…

DeepSeek-R1-0528重磅升级:三大突破重新定义AI生产力

2025年5月28日&#xff0c;中国AI领军企业深度求索&#xff08;DeepSeek&#xff09;正式发布DeepSeek-R1-0528版本&#xff0c;这是继2025年1月R1模型登顶中美App Store后&#xff0c;DeepSeek在通用大模型领域的又一次战略级突破。此次升级虽为小版本迭代&#xff0c;却在推理…

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …

中国西部逐日1 km全天候地表温度数据集(TRIMS LST-TP;2000-2024)

时间分辨率&#xff1a;日空间分辨率&#xff1a;100m - 1km共享方式&#xff1a;开放获取数据大小&#xff1a;474.31 GB数据时间范围&#xff1a;2000-01-01 — 2024-12-31元数据更新时间&#xff1a;2025-05-31 数据集摘要 青藏高原是全球气候变化的敏感区域。地表温度&…

PPT转图片拼贴工具 v1.0

软件介绍 这个软件的作用就是将单个PPT的每一页转换为单独的图片&#xff0c;然后将图片进行拼接起来。 但是我没有还没有解决一次性处理多个文件。 效果展示如下&#xff1a; 软件安装 软件源码 import os import re import win32com.client from PIL import Imagedef con…

嵌入式学习笔记DAY33(网络编程——TCP)

一、网络架构 C/S &#xff08;client/server 客户端/服务器&#xff09;&#xff1a;由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序&#xff0c;负责提供用户界面和交互逻辑 &#xff0c;接收用户输入&#xff0c;向服务器发送请求&#xff0c;并展示服务…

抛砖引玉:RadarDet4D,NuScenes数据集Radar模态目标检测第二名(即将开源)

这几年一直在关注自动驾驶3D目标检测相关的研究。在NuScenes数据集上有很多经典的模型被提出并得到了验证&#xff0c;纯视觉3D目标检测经典的方法有BEVFormer、BEVDet系列、DETR3D、Sparse4D等工作&#xff0c;基于LiDAR的有CenterPoint、多模态有BEVFusion、DAL、UniTR等。 …

更新Java的环境变量后VScode/cursor里面还是之前的环境变量

最近我就遇到这个问题&#xff0c;这个一般是安装了多个版本的Java&#xff0c;并设置好环境变量&#xff0c;但VScode/cursor内部环境变量却没有改变 解决办法 打开设置&#xff0c;或者直接快捷键CTRL&#xff0c;搜索Java:Home编辑settings.json文件 把以下部分改为正确的…

线程的基础知识

进程和线程的区别&#xff1f; 从实例去引入我们的进程和线程的概念&#xff0c;说出进程和线程的关系&#xff0c;引出线程&#xff0c;说出两者的内存分配占用&#xff0c;上下文切换的区别 当操作系统把我们磁盘中的程序加载到我们的内存当中&#xff0c;为其分配内存空间&a…

x86 汇编中的【条件跳转指令】:从基础到扩展的全面解析(查表版)

为了彻底覆盖 x86 架构中所有条件跳转指令&#xff0c;包括 8086 到现代 x86-64 的全部变体&#xff0c;我重新整理了分类体系&#xff0c;并补充了鲜为人知的指令变体、操作数大小前缀和历史演进。 本文需要运用的知识(需要详细了解可点击对应的点)&#xff1a; flags寄存器…

FPGA点亮ILI9488驱动的SPI+RGB接口LCD显示屏(一)

FPGA点亮ILI9488驱动的SPIRGB接口LCD显示屏 ILI9488 RGB接口初始化 目录 前言 一、ILI9488简介 二、3线SPI接口简介 三、配置寄存器介绍 四、手册和初始化verilog FPGA代码 总结 前言 ILI9488是一款广泛应用于嵌入式系统和电子设备的彩色TFT LCD显示控制器芯片。本文将介…

Git忽略规则.gitignore不生效解决

我在gitlab中新建了一个项目仓库&#xff0c;先把项目文件目录绑定到仓库&#xff0c;并全部文件都上传到了仓库中。 然后又从别的项目复制了忽略文件配置过来&#xff0c;怎么搞他都不能生效忽略我不要提交仓库的文件。 从网上查到说在本地仓库目录中&#xff0c;打开命…

记一个判决书查询API接口的开发文档

一、引言 在企业风控、背景调查、尽职调查等场景中&#xff0c;判决书查询是一个非常重要的环节。通过判决书查询&#xff0c;可以了解个人或企业的司法涉诉情况&#xff0c;为风险评估提供数据支持。本文将详细介绍如何开发和使用一个司法涉诉查询API接口&#xff0c;包括客户…

mac版excel如何制作时长版环形图

设置辅助列 创建簇状柱形图 将辅助列绘制在次坐标轴 工作时长在主坐标轴&#xff0c;右键分别更改图表类型为圆环。 辅助列圆环全部为灰色&#xff0c;边框为白色 辅助列设置透明度100% 设置辅助列和工作时长列同样的圆环大小 可得 核心&#xff1a;只要辅助列边框不透明…