一、服务启动流程零代码仅需配置文件和依赖。顺序固定由框架保证。一旦某个步骤失败如 XML 解析错误整个启动失败。二、新增代码跑通流程全手动需熟悉 MyBatis 映射规则、Spring 注解。编译时和运行时都可能出错如 XML 重复 id、SQL 语法错误、依赖注入循环等。结合启动流程新增代码必须符合启动流程的预期如 XML 位置必须在 mapperLocations 扫描路径内。三、 MyBatis 映射规则统一使用 XML 管理复杂映射尤其是动态 SQL 和关联查询注解适合简单查询。避免注解和 XML 混用除非明确分开 id。为每个表/模块独立一个 Mapper XML 片段 id 在同一文件内唯一。启用下划线转驼峰减少冗余的 resultMap。使用 Param 明确命名多参数提高可读性且避免参数顺序问题。开启 MyBatis 日志logging.level.com.example.mapperDEBUG快速定位映射错误。【基础映射resultType 与 resultMap】方式一resultType查询结果列名与 Java 属性名一致或通过 autoMapping 能匹配自动映射列名 user_name → 属性 userName需开启下划线转驼峰方式二resultMap列名与属性名不一致、需要复杂关联映射、类型转换控制显式定义 可指定 id、result、association、collection!-- resultType 自动映射 --selectidselectUserresultTypecom.example.Userselect user_id, user_name from user/select!-- resultMap 显式映射 --resultMapiduserMaptypeUseridcolumnuser_idpropertyuserId/resultcolumnuser_namepropertyuserName//resultMapselectidselectUserMapresultMapuserMapselect user_id, user_name from user/select【属性映射细节】下划线转驼峰自动映射全局配置启用后user_name → userName。mybatis:configuration:map-underscore-to-camel-case:true类型处理器TypeHandler 用法【参数映射】参数映射 指的是将 Java 方法中的实际参数值安全、正确地传递给 SQL 语句中占位符 #{…} 的过程。这是 MyBatis 执行 SQL 前的重要环节直接关系到 SQL 能否正确执行以及是否安全防 SQL 注入。在 Spring Boot MyBatis 注解/XML 混合开发中大多数情况下MyBatis 通过反射或 Param 注解能自动推断参数类型不需要显式写 parameterType仅在遇到参数为 null 导致异常或使用旧版 MyBatis 时才显式指定。方式一单个参数 xml的SQL语句中直接使用 #{任意名称}基础类型示例selectidgetUserByIdparameterTypelongresultTypeUserselect * from user where id #{id}/select对象示例自动读取对象的属性insertidinsertUserparameterTypeUserinsert into user(name, age) values(#{name}, #{age})/insertMap示例selectidgetUserparameterTypemapresultTypeUserselect * from user where id #{id}/select方式二 多个参数必须使用 Param。接口中通过 Param 重命名入参的名称xml的sql语句直接使用 #{属性名}UsergetUser(Param(uid)Longid,Param(name)Stringusername);selectidgetUserresultTypeUserselect * from user where id #{uid} and name #{name}/select【动态SQL】场景一 动态生成WHERE子句自动处理 AND 前缀去除多余的 AND/ORwhereiftestname ! null and name ! AND name LIKE CONCAT(%, #{name}, %)/ififtestage ! nullAND age #{age}/if/where场景二 动态生成 SET 子句自动去除多余逗号用于更新setiftestname ! nullname #{name},/ififtestage ! nullage #{age},/if/set场景三 多条件分支等价于 switch-case-defaultselectidselectUsersOrderByresultTypeUserSELECT * FROM userchoosewhentestorderField nameORDER BY name/whenwhentestorderField ageORDER BY age/whenotherwiseORDER BY id/otherwise/choose/select场景四 遍历集合foreachcollectionlistitemidopen(separator,close)#{id}/foreach场景五 绑定变量避免在 Java 代码中手动拼接selectidsearchUsersresultTypeUserbindnamepatternvalue% keyword %/SELECT * FROM user WHERE name LIKE #{pattern}/select场景六 自定义前缀、后缀、覆盖规则 自定义前缀、后缀、覆盖规则【关联映射】针对 SQL 语句执行结果的映射MyBatis 中的 一对一、一对多、多对多通常拆解为两个一对多 映射其本质就是 将 SQL 查询返回的扁平结果集多表连接后的表状数据转换为 Java 对象图。关联映射的输入SQL 语句执行后返回的 ResultSet扁平表结构。关联映射的输出具有嵌套关系的 Java 对象图。实现方式在 中定义 或 子标签指定子对象的属性、列映射以及如何区分不同行通过 标签。优势避免手动循环组装对象MyBatis 自动完成。场景一一对一classUser{privateLongid;privateRolerole;// 嵌套对象}resultMapiduserWithRoleMaptypeUseridcolumnidpropertyid/resultcolumnnamepropertyname/associationpropertyrolejavaTypeRoleidcolumnrole_idpropertyid/resultcolumnrole_namepropertyname//association/resultMapselectidgetUserWithRoleresultMapuserWithRoleMapSELECT u.id, u.name, r.id as role_id, r.name as role_name FROM user u LEFT JOIN role r ON u.role_id r.id WHERE u.id #{id}/select场景二一对多classUser{privateLongid;privateListOrderorders;}resultMapiduserWithOrdersMaptypeUseridcolumnidpropertyid/collectionpropertyordersofTypeOrderidcolumnorder_idpropertyid/resultcolumnorder_amountpropertyamount//collection/resultMapselectidgetUserWithOrdersresultMapuserWithOrdersMapSELECT u.id, o.id as order_id, o.amount as order_amount FROM user u LEFT JOIN orders o ON u.id o.user_id WHERE u.id #{id}/select场景三多对多 拆分为两个一对多或使用中间表关联。四、常见问题定位【报错一】[2026-05-22T06:52:08.12308:00 WARN 18792 — [study3] [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘authController’: Unsatisfied dependency expressed through field ‘userService’: Error creating bean with name ‘userService’: Unsatisfied dependency expressed through field ‘userMapper’: Error creating bean with name ‘userMapper’ defined in file [D:\demo2026\study3\study3\target\classes\com\example\study3\mapper\UserMapper.class]: Cannot resolve reference to bean ‘sqlSessionTemplate’ while setting bean property ‘sqlSessionTemplate’问题定位查看 Spring Boot 自动配置报告在 application.properties 中添加debugtrue重启应用控制台查看日志a. 关键字 DataSourceAutoConfiguration出现在 Negative matches 中b. 关键字 MyBatisAutoConfiguration出现在Positive matches 中解释sqlSessionTemplate Bean ——自动配置类匹配了但在实际创建 SqlSessionTemplate Bean 的过程中发生了异常导致该 Bean 最终没有被注册到容器中。日志说明类路径中存在 MyBatis 核心类存在唯一的 DataSource Bean没有自定义的 SqlSessionFactory 和 SqlSessionTemplate理论上 Spring 会自动创建 sqlSessionTemplate Bean但实际却失败了这说明 Bean 的实例化过程中抛出了异常可能是创建 SqlSessionFactory 时失败导致 sqlSessionTemplate 无法创建。c. 关键字 ‘sqlSessionFactory’根本原因TaskCheckResultMapper.xml 这个 MyBatis 映射文件解析失败了导致 sqlSessionFactory 无法创建进而引发 sqlSessionTemplate Bean 缺失最终导致 UserMapper 创建失败d. 关键字 Failed to parse mapping resource异常Mapped Statements collection already contains key com.example.study3.mapper.TaskCheckResultMapper.update解释MyBatis 中已经存在一个 id 为 update 的映射语句当尝试再次添加时发生冲突。这通常是因为 同一个 Mapper 接口中注解和 XML 定义了相同 id 的 SQL 操作。异常Error parsing Mapper XML. The XML location is ‘file [xxx.xml]’. Cause: java.lang.IllegalArgumentException: XML fragments parsed from previous mappers already contains key com.解释xml中 被定义了两次导致 MyBatis 解析时出现重复键冲突。通过注解定义方式MapperpublicinterfaceTaskCheckResultMapper{Insert(INSERT INTO task_check_results (execution_id, checker_user_id, check_time, score, level, feedback, auto_checked, details_json) VALUES (#{executionId}, #{checkerUserId}, #{checkTime}, #{score}, #{level}, #{feedback}, #{autoChecked}, #{detailsJson}))Options(useGeneratedKeystrue,keyPropertycheckId)intinsert(TaskCheckResultresult);Select(SELECT * FROM task_check_results WHERE execution_id #{executionId})TaskCheckResultselectByExecutionId(LongexecutionId);Update(UPDATE task_check_results SET score #{score}, level #{level}, feedback #{feedback}, details_json #{detailsJson} WHERE check_id #{checkId})intupdate(TaskCheckResultresult);Delete(DELETE FROM task_check_results WHERE execution_id #{executionId})intdeleteByExecutionId(LongexecutionId);}xml方式?xml version1.0 encodingUTF-8?!DOCTYPEmapperPUBLIC-//mybatis.org//DTD Mapper 3.0//ENhttp://mybatis.org/dtd/mybatis-3-mapper.dtdmappernamespacecom.example.study3.mapper.TaskCheckResultMapperresultMapidBaseResultMaptypecom.example.study3.entity.TaskCheckResultidcolumncheck_idpropertycheckId/resultcolumnexecution_idpropertyexecutionId/resultcolumnchecker_user_idpropertycheckerUserId/resultcolumncheck_timepropertycheckTime/resultcolumnscorepropertyscore/resultcolumnlevelpropertylevel/resultcolumnfeedbackpropertyfeedback/resultcolumnauto_checkedpropertyautoChecked/resultcolumndetails_jsonpropertydetailsJson//resultMapinsertidinsertuseGeneratedKeystruekeyPropertycheckIdINSERT INTO task_check_results (execution_id, checker_user_id, check_time, score, level, feedback, auto_checked, details_json) VALUES (#{executionId}, #{checkerUserId}, #{checkTime}, #{score}, #{level}, #{feedback}, #{autoChecked}, #{detailsJson})/insertselectidselectByExecutionIdresultMapBaseResultMapSELECT * FROM task_check_results WHERE execution_id #{executionId}/selectupdateidupdateUPDATE task_check_results SET score #{score}, level #{level}, feedback #{feedback}, details_json #{detailsJson} WHERE check_id #{checkId}/updatedeleteiddeleteByExecutionIdDELETE FROM task_check_results WHERE execution_id #{executionId}/delete/mapper