MyBatis查询操作实战:从基础配置到动态SQL与性能优化
1. 从“查”开始MyBatis查询操作的核心价值与常见误区如果你刚接触MyBatis或者已经用它写过不少增删改但总觉得查询这块儿用起来有点“别扭”——要么是结果映射总出问题要么是动态SQL写得不够优雅再或者性能上总觉得差点意思——那你来对地方了。查询作为数据持久层最核心、最高频的操作其实现方式直接决定了应用的数据访问效率和代码的可维护性。很多人把MyBatis的查询简单地理解为“写个SQL返回个List”这其实错过了它设计上的许多精妙之处。我见过不少项目查询代码写得像“面条”各种if判断嵌套在Java代码里拼接SQL字符串不仅难以维护SQL注入的风险也悄然滋生。也有的项目过度依赖“自动映射”导致数据库字段名的一个小小改动就引发运行时异常。MyBatis的强大在于它在“便捷”和“灵活”之间找到了一个平衡点它用XML或注解帮你管理SQL用结果映射处理复杂的对象关系用动态SQL应对多变的查询条件同时又让你对最终执行的SQL拥有完全的控制权。今天我们就抛开那些笼统的概念直接深入到三种最典型查询场景的肌理中查询所有、查询单行、条件查询。我会结合我踩过的坑和优化经验让你不仅知道怎么写更明白为什么这么写以及怎么写更好。2. 基石搭建MyBatis查询环境的核心配置与Mapper定义在动手写查询之前确保你的“工作台”是稳固的。很多查询时遇到的诡异问题根源往往在配置阶段就埋下了。这里没有太多炫技的东西但每一步都至关重要。2.1 数据源与SqlSessionFactory查询的发动机一切始于SqlSessionFactory它是MyBatis的“发动机工厂”。通常我们在Spring Boot项目中通过配置类或application.yml来定义它。核心是数据源和Mapper接口的扫描路径。# application.yml 示例 spring: datasource: url: jdbc:mysql://localhost:3306/your_database?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/Shanghai username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver mybatis: # 重要指定Mapper XML文件的位置。如果Mapper接口和XML文件在同一包下且命名相同可以省略。但显式指定更安全。 mapper-locations: classpath:mapper/*.xml # 重要配置类型别名包这样在XML里就不用写全限定类名了 type-aliases-package: com.example.demo.entity configuration: # 开启驼峰命名自动映射。这是处理数据库字段名user_name到Java属性名userName转换的利器。 map-underscore-to-camel-case: true # 建议开启可以在控制台打印执行的SQL调试神器。 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl注意map-underscore-to-camel-case是一个非常有用的配置但它不是万能的。当你的查询涉及复杂的联表、结果集包含同名字段或者你使用了resultMap进行自定义映射时这个配置可能会失效或产生冲突。我的经验是对于简单的单表查询可以依赖它但对于复杂查询显式定义resultMap是更稳妥的做法。2.2 Mapper接口与XML的绑定契约的签订MyBatis的核心思想之一是将接口方法与SQL语句绑定。假设我们有一个User实体和一个UserMapper接口。// User.java Data // 使用Lombok简化代码 public class User { private Long id; private String userName; // 对应数据库 user_name private Integer age; private String email; } // UserMapper.java Mapper // Spring Boot中标识这是一个MyBatis Mapper接口 public interface UserMapper { // 方法1查询所有用户 ListUser selectAll(); // 方法2根据ID查询单个用户 User selectById(Param(id) Long id); // 方法3条件查询用户列表 ListUser selectByCondition(User user); }接口定义好了SQL在哪里有两种主流方式XML和注解。对于简单的、固定的SQL注解非常简洁但对于动态SQLXML的可读性和灵活性远胜于注解。考虑到我们后续要深入动态SQL这里统一使用XML方式。在resources/mapper/目录下创建UserMapper.xml。?xml version1.0 encodingUTF-8 ? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.example.demo.mapper.UserMapper !-- 后续的SQL定义将在这里进行 -- /mapper关键点是namespace属性它必须完全对应你的Mapper接口的全限定名。这是MyBatis将XML中的SQL语句与接口方法连接起来的桥梁。如果这里写错你会遇到经典的“Invalid bound statement (not found)”错误。3. 查询所有数据selectAll的实践与性能隐忧“查询所有”听起来最简单但如果不加思考它可能成为性能的“黑洞”。我们先从基础实现开始。3.1 基础实现与结果映射在UserMapper.xml的mapper标签内添加我们的第一个查询语句。!-- 1. 查询所有用户 -- select idselectAll resultTypeUser SELECT id, user_name, age, email FROM user /selectidselectAll 必须与UserMapper接口中的方法名selectAll一致。resultTypeUser 指定返回值类型。因为我们配置了type-aliases-package所以可以直接写类名User。MyBatis会创建User对象的列表ListUser并将查询结果自动映射进去。在Service层调用它Service public class UserService { Autowired private UserMapper userMapper; public ListUser getAllUsers() { return userMapper.selectAll(); } }看起来完美对吧但这里有几个新手容易忽略的细节字段匹配resultType依赖自动映射。确保SQL查询的列名如user_name能通过驼峰规则或完全匹配映射到User对象的属性userName。如果数据库有create_time字段而实体类没有没关系多出的字段会被忽略。但反之如果实体类有某个属性而SQL没查询对应的列该属性将为null。SQL注入在这个简单的例子里SQL是静态的没有参数所以没有注入风险。但请记住这个原则永远不要通过字符串拼接的方式来构造查询所有语句中的条件比如SELECT * FROM user WHERE name ‘” name “‘这是大忌。3.2 “查询所有”的陷阱与分页考量SELECT * FROM user在测试环境几十条数据时跑得飞快但在生产环境用户表可能有百万、千万行。一次性加载所有数据到内存会导致内存溢出OOM 应用服务器内存被撑爆。数据库压力 巨大的结果集传输占用大量网络IO和数据库连接时间。响应缓慢 用户前端等待时间极长。所以真正的“查询所有”在业务中极少见。更常见的需求是“分页查询所有”。在MyBatis中我们有几种方式实现分页方案一使用MyBatis-Plus等插件推荐MyBatis-Plus内置了强大的分页插件配置简单功能强大。方案二使用PageHelper国内流行这是一个非常方便的第三方分页插件通过拦截器实现几乎零侵入代码。方案三手动编写分页SQL如果你需要极致的控制或处于一个非常简单的环境可以手动传参。!-- UserMapper接口添加方法 -- ListUser selectAllByPage(Param(offset) Integer offset, Param(pageSize) Integer pageSize); !-- 对应的XML -- select idselectAllByPage resultTypeUser SELECT id, user_name, age, email FROM user LIMIT #{offset}, #{pageSize} /select实操心得 对于大多数项目我强烈推荐使用MyBatis-Plus。它的分页配置一行代码搞定并且能自动优化count查询支持多种数据库方言。自己手写分页SQL不仅容易出错比如分页参数计算错误而且在不同的数据库MySQL的LIMIT、Oracle的ROWNUM、PostgreSQL的LIMIT/OFFSET上需要写不同的SQL维护成本高。记住selectAll在实际编码中几乎总是和limit成对出现。4. 精确获取单条记录selectById的细节与空值处理根据主键ID查询单条记录是仅次于查询列表的高频操作。它通常用于详情查看、数据编辑前的回显等场景。4.1 基础实现与Param注解在UserMapper.xml中继续添加!-- 2. 根据ID查询单个用户 -- select idselectById resultTypeUser SELECT id, user_name, age, email FROM user WHERE id #{id} /select这里的#{id}是一个占位符MyBatis会使用预编译语句PreparedStatement来设置参数有效防止SQL注入。它对应接口方法User selectById(Param(“id”) Long id);中的参数。Param(“id”)注解在这里起到了关键作用它显式地告诉MyBatis这个参数在SQL中的名字叫做“id”。如果方法只有一个参数并且你在XML中就用这个参数名有时可以省略Param。但我的强烈建议是始终使用Param注解来明确参数名。这能避免很多因参数名编译后丢失特别是在JDK8以上使用了-parameters参数除外导致的诡异问题也让代码意图更清晰。4.2 单条查询的边界情况与结果处理这个方法返回的是单个User对象而不是List。这里有几个重要的边界情况需要处理查询结果为空无此ID MyBatis会返回null。调用方必须做好空值判断否则后续的user.getUserName()就会抛出NullPointerException。User user userMapper.selectById(99999L); if (user null) { throw new BusinessException(用户不存在); } // 安全地使用user查询结果不止一条 如果你的id字段不是主键或唯一约束理论上可能返回多行。MyBatis在这种情况下会抛出TooManyResultsException异常。这通常意味着你的表设计或查询条件有问题。确保where条件能唯一定位一条记录。使用resultMap进行复杂映射进阶 当查询需要关联其他表或者字段映射关系复杂时resultType就不够用了。这时需要定义resultMap。假设每个User拥有多个Order我们想在一次查询中获取用户及其所有订单一对多。这虽然超出了“查询单行”的范畴但展示了resultMap的强大。首先定义Order实体和扩展的User实体包含订单列表。!-- 定义一个名为 UserWithOrdersResultMap 的 resultMap -- resultMap idUserWithOrdersResultMap typeUser id propertyid columnid/ result propertyuserName columnuser_name/ result propertyage columnage/ result propertyemail columnemail/ !-- collection 处理一对多关系 -- collection propertyorderList ofTypeOrder id propertyorderId columnorder_id/ result propertyorderNo columnorder_no/ result propertyamount columnamount/ /collection /resultMap !-- 使用 resultMap 而不是 resultType -- select idselectUserWithOrdersById resultMapUserWithOrdersResultMap SELECT u.*, o.order_id, o.order_no, o.amount FROM user u LEFT JOIN order o ON u.id o.user_id WHERE u.id #{id} /select注意 这种联表查询在数据量大时需谨慎可能产生“N1”查询问题。对于大数据量关联分步查询使用association/collection的select属性通常是更好的选择但这属于更高级的优化话题。对于简单的selectByIdresultType足矣。5. 动态条件查询selectByCondition与动态SQL的精髓条件查询是业务系统中最灵活、最复杂的部分。用户可能根据姓名、年龄范围、邮箱等多种条件组合筛选而且这些条件可能为空。这就是动态SQL大显身手的地方。5.1if标签构建灵活的WHERE子句回到我们的UserMapper.selectByCondition(User user)方法。我们希望实现如果user对象的某个属性不为空则将其作为过滤条件。!-- 3. 条件查询用户列表 -- select idselectByCondition resultTypeUser parameterTypeUser SELECT id, user_name, age, email FROM user WHERE 11 if testuserName ! null and userName ! AND user_name LIKE CONCAT(%, #{userName}, %) /if if testage ! null AND age #{age} /if if testemail ! null and email ! AND email #{email} /if /selectparameterTypeUser 可以省略MyBatis通常能自动推断。WHERE 11 这是一个“小技巧”。目的是让后面的if标签都能统一地用AND开头避免第一个条件为空时SQL出现WHERE AND的错误。虽然有些人觉得不优雅但在纯if标签的场景下非常实用。if test...test属性内是OGNL表达式用于判断条件是否成立。userName ! null and userName ! 是常见的判空和非空字符串写法。调用示例User queryCondition new User(); queryCondition.setUserName(张); // 查询姓名包含“张”的用户 queryCondition.setAge(25); // 同时年龄等于25 ListUser users userMapper.selectByCondition(queryCondition); // 生成的SQL: SELECT ... FROM user WHERE 11 AND user_name LIKE %张% AND age 255.2where,set,trim更优雅的动态SQL标签WHERE 11毕竟是个取巧的办法。MyBatis提供了更专业的where标签来处理这个问题。select idselectByConditionV2 resultTypeUser SELECT id, user_name, age, email FROM user where if testuserName ! null and userName ! AND user_name LIKE CONCAT(%, #{userName}, %) /if if testage ! null AND age #{age} /if if testemail ! null and email ! AND email #{email} /if /where /selectwhere标签会做两件事只有当其内部至少有一个条件成立时才会插入WHERE关键字。会自动去除掉紧跟其后第一个条件的AND或OR。这样我们就不用写11并且每个条件前都可以放心地加AND。类似地set标签用于动态更新语句会自动处理末尾的逗号。trim标签则更通用可以自定义前缀、后缀以及要覆盖的字符串用于处理更复杂的场景。5.3choose, when, otherwise实现分支选择有时我们的逻辑不是简单的“如果…就加上”而是“多选一”。例如按照优先级查询先按姓名精确匹配如果没找到再按姓名模糊匹配最后按邮箱匹配。select idselectByConditionV3 resultTypeUser SELECT id, user_name, age, email FROM user where choose when testuserName ! null and userName ! user_name #{userName} !-- 优先精确匹配 -- /when when testuserName ! null and userName ! user_name LIKE CONCAT(%, #{userName}, %) !-- 其次模糊匹配 -- /when otherwise email #{email} !-- 最后匹配邮箱 -- /otherwise /choose if testage ! null !-- 其他条件可以额外附加 -- AND age #{age} /if /where /selectchoose类似于Java中的switch-case只会执行第一个满足条件的when或者执行otherwise。5.4 模糊查询与性能注意注意上面我们用到了LIKE CONCAT(‘%’, #{name}, ‘%’)来进行模糊查询。这是防止SQL注入的正确写法使用#{}占位符。直接写LIKE ‘%${name}%’是危险的因为${}是字符串替换会有注入风险。但是前导模糊查询LIKE ‘%xxx’是无法使用数据库索引的会导致全表扫描数据量大时性能极差。如果业务允许尽量使用后导模糊查询LIKE ‘xxx%’这样可以利用索引。或者考虑引入Elasticsearch等全文检索引擎。6. 避坑指南MyBatis查询中的典型问题与排查思路即使掌握了语法在实际开发中你还是会遇到各种各样的问题。下面是我总结的几个高频“坑点”和排查思路。6.1 “Invalid bound statement (not found)” 错误排查这是MyBatis新手遇到最多的错误意思是“找不到绑定的SQL语句”。排查路径如下检查Mapper接口与XML的namespace 确保XML中mapper namespace”…”的值完全等于Mapper接口的全限定名包括包名一个字母都不能错。检查方法名与SQL ID 确保XML中select id”…”的值与接口方法名一致。检查XML文件位置与配置 确保UserMapper.xml文件位于mybatis.mapper-locations配置的路径下如classpath:mapper/。在Maven项目中确保XML文件放在src/main/resources对应的目录下而不是src/main/java。检查编译结果 清理项目并重新编译mvn clean compile确保XML文件被打包到最终的target/classes或build/classes目录下。检查IDEA等IDE的配置 有时IDE的“资源过滤”可能有问题可以尝试Rebuild Project。6.2 参数传递与Param注解的玄机单个基本类型参数 可以不用Param在XML中直接用#{参数名}或#{_parameter}引用。但为了清晰建议都用Param。多个参数必须使用Param否则在XML中只能通过#{arg0},#{arg1}或#{param1},#{param2}来访问可读性极差。传递对象 如selectByCondition(User user)在XML中可以直接使用对象的属性名如#{userName}MyBatis会通过OGNL表达式user.userName来获取值。传递Map 在XML中直接使用Map的key如#{nameKey}。这在动态条件非常多时偶尔有用但不如对象直观。6.3 结果映射失败属性为null的常见原因数据库字段名与对象属性名不匹配 这是最常见的原因。检查是否开启了map-underscore-to-camel-case或者是否在resultMap中正确配置了映射。SQL查询未返回该列 检查你的SELECT语句是否漏掉了某个字段。特别是当你用了SELECT *但后来数据库表增加了字段而实体类未更新时不会报错但新增字段不会被映射。类型不匹配 数据库是TINYINT(1)Java中用Boolean接收数据库是BIGINTJava中用Integer接收。这会导致映射失败或精度丢失。嵌套对象映射问题 在使用association或collection进行复杂映射时如果嵌套对象的属性映射没配好整个嵌套对象都可能为null。调试技巧 开启MyBatis的SQL日志配置log-impl: StdOutImpl仔细核对打印出的SQL语句和参数看是否和你预期的一致。也可以临时将resultType改为map看查询返回的ListMapString, Object里到底有哪些键值对。6.4 动态SQL中的test表达式陷阱if test”…”中的test是OGNL表达式它和Java语法有些微差别判断字符串是否为空name ! null and name ! ‘’。注意单引号。判断集合是否为空list ! null and list.size() 0。注意与and和或or 要用and和or而不是和||。调用静态方法格式为全限定类名方法名(参数)如java.util.Objectsequals(str1, str2)但这样写很繁琐尽量避免。7. 性能优化与进阶思考让查询飞起来写出来能用的SQL只是第一步写出高性能的SQL才是进阶之路。7.1 善用索引与避免全表扫描这是数据库层面的优化但需要在写MyBatis SQL时时刻谨记为WHERE子句、ORDER BY子句、JOIN关联字段建立索引。避免在索引列上使用函数或计算如WHERE YEAR(create_time) 2023会导致索引失效。应改为范围查询WHERE create_time ‘2023-01-01’ AND create_time ‘2024-01-01’。谨慎使用OR可能导致索引失效考虑用UNION改写。像前面提到的避免前导模糊查询LIKE ‘%xxx’。7.2 分页查询的深度优化简单的LIMIT offset, size在offset非常大时比如第100万条开始性能会急剧下降因为MySQL需要先扫描并丢弃前面的大量记录。优化方案使用索引覆盖扫描 子查询适用于有自增主键或有序字段的表SELECT * FROM user WHERE id (SELECT id FROM user ORDER BY id LIMIT 1000000, 1) LIMIT 10;记录上一页的最大ID适用于“上一页/下一页”式分页SELECT * FROM user WHERE id #{lastMaxId} ORDER BY id LIMIT 10;这种“游标分页”方式性能极佳但不支持直接跳转到任意页码。7.3 关联查询的“N1”问题与解决方案这是ORM框架的一个经典问题。假设你要查询10个用户以及每个用户的所有订单。如果你先查询用户列表1次查询再循环为每个用户查询订单N次查询这就是N1次查询性能极差。MyBatis的解决方案嵌套结果映射一次查询联表 就像前面resultMap中collection的例子一次SQL联表查询出所有数据。缺点是当关联数据很多时结果集会有大量冗余数据用户信息重复可能影响传输和内存。嵌套查询分步查询 在resultMap中配置collection时使用select属性指定另一个Mapper方法。resultMap idUserWithOrdersLazyResultMap typeUser id propertyid columnid/ !-- ... 其他基础字段映射 ... -- collection propertyorderList ofTypeOrder selectcom.example.demo.mapper.OrderMapper.selectByUserId columnid/ /resultMap select idselectUserByIdWithLazyOrders resultMapUserWithOrdersLazyResultMap SELECT * FROM user WHERE id #{id} /select这样首先执行查询用户的SQL。只有当程序真正访问user.getOrderList()时MyBatis才会执行selectByUserId去查询订单。这实现了“懒加载”。你可以通过配置fetchType”lazy”或fetchType”eager”来控制加载行为。嵌套查询可以避免数据冗余但会产生多次数据库往返1N次如果N很大且你确实需要所有关联数据性能可能更差。需要根据数据量和业务场景权衡。7.4 考虑使用MyBatis-Plus等增强工具对于日常开发MyBatis-PlusMP能极大提升效率。它内置了通用Mapper像selectById、selectList条件查询这些方法你都不用写了。它的QueryWrapper或LambdaQueryWrapper提供了一种更符合Java习惯的、类型安全的方式来构建动态查询条件避免了在XML中写大量if标签。// 使用MyBatis-Plus的LambdaQueryWrapper示例 LambdaQueryWrapperUser wrapper new LambdaQueryWrapper(); wrapper.like(StringUtils.isNotBlank(user.getUserName()), User::getUserName, user.getUserName()) .eq(user.getAge() ! null, User::getAge, user.getAge()) .eq(StringUtils.isNotBlank(user.getEmail()), User::getEmail, user.getEmail()); ListUser list userMapper.selectList(wrapper);代码更简洁而且编译时就能检查属性名是否正确避免了XML中属性名拼写错误到运行时才发现的问题。当然MP并不能完全替代原生MyBatis在复杂SQL和极致优化上的灵活性但它能覆盖80%的日常场景让开发更聚焦于业务逻辑。查询是MyBatis的起点也是最能体现其设计哲学的地方。从简单的select *到复杂的动态SQL与结果映射每一步都需要理解其背后的原理和权衡。记住没有最好的写法只有最适合当前场景的写法。多思考数据库执行计划多观察生成的SQL日志不断从业务需求和性能瓶颈中寻找平衡点你就能越来越得心应手地驾驭MyBatis让它成为你手中高效、可靠的数据访问利器而不是bug和性能问题的来源。

相关新闻

Wpf中ObservableCollection集合赋值遇到的坑

Wpf中ObservableCollection集合赋值遇到的坑

在Wpf中使用ObservableCollection定义数组数据时,由于该类型变量已继承 INotifyCollectionChanged,所以无需重写get,set属性,只需声明get,set属性即可实现变量在改变时通知到界面,所以常常被用来定义需要Datagrid控件显示的内容&a…

2026/7/31 5:31:57阅读更多 →
Step-Voice语音大模型:多语言TTS与音色克隆部署实践

Step-Voice语音大模型:多语言TTS与音色克隆部署实践

这次我们来看阶跃星辰联合举办的Voice AI Night活动。这个活动聚焦于语音AI技术的最新进展,特别是阶跃星辰发布的Step-Voice语音大模型。对于关注本地语音AI部署、多语言TTS、音色克隆和实时语音交互的开发者来说,这次活动展示的技术方案和开放能力值得重…

2026/7/31 5:31:57阅读更多 →
Fastboot与Fastbootd深度解析:安卓底层刷机协议与动态分区管理

Fastboot与Fastbootd深度解析:安卓底层刷机协议与动态分区管理

1. 项目概述:从“砖头”到“神器”的救赎之路如果你曾经因为误操作把安卓手机刷成了“砖头”,或者在系统升级后遇到了无法开机的窘境,那么你一定听说过“Fastboot”这个名字。它就像手机维修师傅工具箱里那把最趁手的螺丝刀,平时不…

2026/7/31 5:31:57阅读更多 →
AI 芯片简报 07.27-07.30:微软赚钱 Meta 烧钱、SOX 四连阴、ARM 爆业绩雷

AI 芯片简报 07.27-07.30:微软赚钱 Meta 烧钱、SOX 四连阴、ARM 爆业绩雷

AI 芯片简报 07.27-07.30:微软赚钱 Meta 烧钱、SOX 四连阴、ARM 爆业绩雷 每期覆盖 2-4 天的 AI 芯片动态(窗口取决于发布日间隔)。个人视角,不追求面面俱到——只讲我认为重要的。周二、四、六更新。 上期:AI 芯片简报…

2026/7/31 6:50:26阅读更多 →
北京地区 GEO 服务能力解读

北京地区 GEO 服务能力解读

北京企业选GEO服务,可以先看哪些能力 说明: 本文由公开资料整理,介绍生成式引擎优化(GEO)相关概念,以及北京尔创互动科技有限公司旗下「客啦啦 GEO」服务方向的能力框架,供企业市场、品牌负责人…

2026/7/31 6:50:26阅读更多 →
电解槽智能监测管理平台方案

电解槽智能监测管理平台方案

铜电解生产中,槽温和槽压是影响产品质量和能耗的关键指标。某工厂部署多套电解槽智能监测装置,能够实现对槽温槽压的在线持续监测,但仍局限于本地监控和人工抄表的传统管理模式中,在故障发现时效与响应能力上仍有很多不足。因此&a…

2026/7/31 6:50:26阅读更多 →
SSRF漏洞原理、攻击手法与防御策略详解

SSRF漏洞原理、攻击手法与防御策略详解

1. SSRF漏洞的本质与危害解析SSRF(Server-Side Request Forgery)服务端请求伪造,本质上是一种由服务端发起非预期网络请求的安全缺陷。当攻击者能够控制服务器发出的请求目标时,就可能导致内网探测、数据泄露甚至远程代码执行等严…

2026/7/31 6:50:26阅读更多 →
VMware Workstation Pro 17 安装 Windows 11 虚拟机保姆级教程

VMware Workstation Pro 17 安装 Windows 11 虚拟机保姆级教程

1. 项目概述:为什么我们需要一台Windows 11虚拟机?最近在折腾一些开发环境,或者想测试新软件又怕搞乱主力机,又或者需要一台干净的Windows系统来运行某些特定应用,你是不是也有过这些念头?直接装双系统太麻…

2026/7/31 6:50:26阅读更多 →
Zynq R5双核温控与OpenAMP通信实战指南

Zynq R5双核温控与OpenAMP通信实战指南

1. 先搞清楚 Zynq R5 核温控和 OpenAMP 到底解决什么问题如果你正在用 Zynq-7000 这类带双核 ARM Cortex-R5 的 FPGA 芯片做工业控制、电机驱动或环境监控,最头疼的可能是这两件事:一是怎么让 R5 核稳定读取温度传感器数据并做出实时响应,二是…

2026/7/31 6:48:25阅读更多 →
覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

🔹 工具基础介绍 OpenClaw 是开源生态中一款实用性较强的本地智能工具,凭借本地离线运行、可视化图形操作和任务自动化三大核心特性,赢得了众多用户的青睐。与普通在线对话AI工具不同,它属于能够直接操控本机软硬件的智能数字员工…

2026/7/30 15:03:16阅读更多 →
伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

所谓液压伺服阀体的精密激光焊接,是用激光束对阀座壳体(通常为不锈钢或铝合金)进行密封焊接,使阀体在21-35MPa的高压液压油或压缩气体中长期运行而不发生介质泄漏。液压伺服阀是高端液压系统的"大脑"。从航空航天飞行控…

2026/7/30 12:22:27阅读更多 →
D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx 你是否还在…

2026/7/30 15:13:02阅读更多 →
物理复制比逻辑复制好在哪?数据库复制原理详解

物理复制比逻辑复制好在哪?数据库复制原理详解

数据库复制是把主库数据同步到备库的机制,分为逻辑复制和物理复制两种。逻辑复制传输的是 SQL 语句或行变更事件,物理复制传输的是存储引擎底层的物理日志。阿里云 PolarDB(云原生数据库)采用物理复制,在同步延迟、数据…

2026/7/31 0:00:40阅读更多 →
BilibiliDown:3分钟学会B站视频下载的终极指南

BilibiliDown:3分钟学会B站视频下载的终极指南

BilibiliDown:3分钟学会B站视频下载的终极指南 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader 😳 项目地址: https://gitcode.com/gh_mirrors/bi/Bilib…

2026/7/31 0:00:41阅读更多 →
有哪些游戏数据AI平台?游戏行业Data+AI融合方案盘点

有哪些游戏数据AI平台?游戏行业Data+AI融合方案盘点

当前,游戏行业的“DataAI融合”已从概念验证进入价值落地阶段。根据IDC 2025年数据,中国AI游戏云市场规模已达18.6亿元;同时,游戏研发环节AI渗透率高达86%,生成式AI内容普及率超过50%。面对庞大的市场,游戏…

2026/7/31 0:00:41阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/31 0:49:33阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/31 5:08:18阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/30 15:43:46阅读更多 →