1. 项目缘起为什么Mybatis依赖配置是项目启动的“第一道坎”如果你刚接触Java后端开发或者正准备搭建一个新的Spring Boot项目那么“引入Mybatis并让它跑起来”这件事大概率会成为你遇到的第一个技术小关卡。表面上看这不过是往pom.xml里加几行依赖在application.yml里写几行配置似乎没什么技术含量。但根据我过去几年带团队和排查新手问题的经验恰恰是这“简单”的几步埋下了最多的坑项目启动报ClassNotFoundException、Mapper接口扫描不到、SQL语句执行时报各种奇怪的绑定错误……这些问题十有八九都源于依赖和配置的“差之毫厘”。所以今天我们不聊高深的Mybatis原理也不讲复杂的动态SQL技巧就扎扎实实地把“依赖引入”和“基础配置”这两件最基础、却又最容易被轻视的事情讲透。我会以一个典型的Spring Boot项目为例带你走一遍从零到一的完整配置流程并重点分享那些官方文档不会写、但实际开发中一定会遇到的“坑点”和“最佳实践”。目标是让你配置完一次后以后再遇到同类项目都能在5分钟内搞定并且心里有底知道每一行配置背后的“为什么”。2. 依赖引入不仅仅是“复制粘贴”那么简单很多人引入依赖就是去网上找个例子把dependency标签复制到自己的pom.xml里然后运行mvn clean install。这当然能跑通大部分情况但一旦遇到版本冲突或者需要特定功能时就会一头雾水。我们得搞清楚我们在引入什么以及为什么这么引入。2.1 核心依赖选型Spring Boot官方“亲儿子” vs 原生集成对于Spring Boot项目Mybatis的集成主要有两种官方推荐方式MyBatis Spring Boot Starter这是Mybatis团队为Spring Boot量身定制的起步依赖也是目前最主流、最省心的选择。它帮你自动配置了SqlSessionFactory、SqlSessionTemplate、Mapper扫描器等核心组件你几乎不需要写任何额外的Java配置代码。MyBatis-Spring这是Mybatis与Spring框架集成的原生库。在Spring Boot项目中如果你需要更精细地控制Mybatis的每一个配置环节或者项目本身不是标准的Spring Boot应用比如传统的Spring MVC项目才会选择这种方式。对于99%的Spring Boot项目我们无脑选择第一种。它的GAV坐标如下dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version3.0.3/version !-- 请注意检查最新版本 -- /dependency关键点解析与避坑版本号3.0.x是当前的主要版本线。你必须去 Maven中央仓库 或项目的GitHub Release页面确认最新稳定版。直接使用文中的版本可能不是最新的。“Starter”的含义这个starter包本身是一个“依赖的集合”。你引入它就相当于同时引入了mybatis、mybatis-spring以及Spring Boot的自动配置模块。你可以通过mvn dependency:tree命令查看它具体拉取了哪些依赖避免重复引入导致冲突。与Spring Boot版本的兼容性这是最大的一个坑Mybatis Spring Boot Starter的版本与Spring Boot的版本有严格的对应关系。例如3.0.x的Starter通常要求Spring Boot3.x版本如果你用的是Spring Boot2.7.x那么应该对应使用Starter2.3.x版本。版本不匹配会导致自动配置失效甚至启动失败。一个简单的对照记忆方法是主要版本号尽量对齐Spring Boot 3对应Starter 3 Spring Boot 2对应Starter 2。2.2 数据库驱动依赖别忘了他真正的“搭档”引入了Mybatis它还得知道怎么连接数据库。所以数据库驱动是必不可少的另一个依赖。以最常用的MySQL 8.x为例dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId scoperuntime/scope /dependency关键点解析与避坑scope设为runtime这是一个重要技巧。数据库驱动只在运行期Runtime需要在编译期Compile并不需要。将其作用域设置为runtime可以让你的编译类路径更干净避免一些不必要的传递依赖问题。驱动类名变更MySQL 8重点如果你用的是MySQL 8.0及以上版本驱动类名已经从古老的com.mysql.jdbc.Driver变更为com.mysql.cj.jdbc.Driver。虽然新版本的驱动兼容老的类名但在配置spring.datasource.driver-class-name时显式使用新的类名是更规范的做法。这个细节我们会在配置部分再次强调。其他数据库如果是PostgreSQL依赖是org.postgresql:postgresqlOracle则需要从官方获取ojdbc的依赖。2.3 可选但推荐的依赖让开发更高效除了核心依赖还有一些“锦上添花”的依赖能极大提升开发和调试效率。分页助手 - PageHelper在国内项目中分页查询的需求几乎无处不在。Mybatis本身不提供物理分页而PageHelper是国内最流行的分页插件其Starter集成也非常方便。dependency groupIdcom.github.pagehelper/groupId artifactIdpagehelper-spring-boot-starter/artifactId version2.1.0/version !-- 请注意检查最新版本 -- /dependency引入后在Service层只需要一行代码PageHelper.startPage(pageNum, pageSize)其后的第一个Mybatis查询方法就会自动进行物理分页。它的配置我们稍后再说。代码生成器 - MyBatis Generator (MBG)对于简单的CRUD操作手写每张表的Entity、Mapper接口和XML文件是重复劳动。MBG可以根据数据库表结构自动生成这些样板代码。虽然Spring Boot官方Starter没有直接集成它但它是一个独立的工具通常通过Maven插件或Gradle任务来运行。!-- 在 pom.xml 的 build/plugins 部分添加 -- plugin groupIdorg.mybatis.generator/groupId artifactIdmybatis-generator-maven-plugin/artifactId version1.4.2/version configuration configurationFilesrc/main/resources/generatorConfig.xml/configurationFile overwritetrue/overwrite verbosetrue/verbose /configuration dependencies dependency groupIdcom.mysql/groupId artifactIdmysql-connector-j/artifactId version${mysql.version}/version /dependency /dependencies /plugin然后你需要编写一个generatorConfig.xml文件来配置生成规则。对于新项目使用MBG快速搭建基础代码框架能节省大量时间。3. 核心配置详解连接数据库与定位Mapper依赖加好了接下来就是告诉Mybatis“去哪儿找数据库”和“去哪儿找SQL映射”。这些配置通常写在application.yml或application.properties中。我这里以更清晰的YAML格式为例。3.1 数据源配置建立连接的生命线数据源DataSource是所有数据库操作的起点。Spring Boot已经内置了强大的自动配置。spring: datasource: url: jdbc:mysql://localhost:3306/your_database?useUnicodetruecharacterEncodingutf-8useSSLfalseserverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrue username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver # MySQL 8 使用这个 hikari: connection-timeout: 30000 # 连接超时时间(毫秒) maximum-pool-size: 20 # 连接池最大大小 minimum-idle: 10 # 连接池最小空闲连接数 idle-timeout: 600000 # 连接空闲超时时间(毫秒) max-lifetime: 1800000 # 连接最大生命周期(毫秒)关键点解析与避坑URL参数是重中之重useUnicodetruecharacterEncodingutf-8确保正确处理中文避免乱码。useSSLfalse在本地开发或内网环境中如果MySQL未配置SSL必须设为false否则会连接失败。生产环境应设置为true并提供证书。serverTimezoneAsia/Shanghai解决著名的The server time zone value...错误明确指定服务器时区。allowPublicKeyRetrievaltrueMySQL 8.0后默认使用新的身份验证插件某些客户端需要此参数来获取公钥。生产环境需评估安全性。driver-class-name如前所述MySQL 8建议使用com.mysql.cj.jdbc.Driver。如果你不配置Spring Boot会根据URL自动检测但显式配置更稳妥。HikariCP连接池从Spring Boot 2.0开始默认使用HikariCP它是目前性能最好的Java数据库连接池之一。上述配置项可以优化连接池行为比如maximum-pool-size不宜设置过大通常10-20对于普通应用足够了设置过大会浪费资源并增加数据库压力。3.2 Mybatis自身配置告诉它“规则”这部分配置以mybatis开头是Mybatis Spring Boot Starter特有的配置项。mybatis: # 1. 指定全局配置文件的位置可选但推荐用于集中配置 config-location: classpath:mybatis/mybatis-config.xml # 2. 指定Mapper XML文件的位置**必须** mapper-locations: classpath:mapper/*.xml # 3. 指定实体类别名包强烈推荐 type-aliases-package: com.yourcompany.yourproject.entity # 4. 全局配置项也可以在config-location指定的文件中配置 configuration: map-underscore-to-camel-case: true # 开启驼峰命名自动映射 default-fetch-size: 100 default-statement-timeout: 30 # 5. 执行器类型可选 executor-type: simple关键点解析与避坑mapper-locations这是最容易出错的地方之一。这个配置告诉Mybatis去哪里加载编写SQL的XML映射文件。如果你的XML文件放在resources/mapper/目录下那么classpath:mapper/*.xml这个路径就是正确的。如果路径配错启动时不会报错但执行数据库操作时会抛出令人困惑的Invalid bound statement (not found)异常。我建议使用Ant风格的通配符例如classpath*:mapper/**/*.xml这样可以递归扫描子目录项目结构更灵活。type-aliases-package这个配置太有用了。配置后在XML映射文件中就可以用resultTypeUser代替resultTypecom.yourcompany.yourproject.entity.User大大减少了冗长的全限定类名让XML更清晰。map-underscore-to-camel-case: true这是另一个必选项。数据库字段习惯使用user_name这样的下划线命名而Java实体类属性习惯使用userName这样的驼峰命名。开启这个选项Mybatis会自动进行映射你就不需要在每一个result标签中手动指定property和column的对应关系了能省去大量重复劳动。config-location对于简单的项目你可以像上面一样直接在application.yml中使用mybatis.configuration子项进行配置。但对于配置项较多或者需要配置插件如PageHelper、类型处理器等复杂情况推荐使用一个独立的mybatis-config.xml文件并通过config-location指定。这样配置更集中、更清晰。一个简单的mybatis-config.xml可能长这样?xml version1.0 encodingUTF-8? !DOCTYPE configuration PUBLIC -//mybatis.org//DTD Config 3.0//EN http://mybatis.org/dtd/mybatis-3-config.dtd configuration settings !-- 开启驼峰命名映射 -- setting namemapUnderscoreToCamelCase valuetrue/ !-- 打印查询语句 -- setting namelogImpl valueSTDOUT_LOGGING/ /settings plugins !-- 分页插件配置 -- plugin interceptorcom.github.pagehelper.PageInterceptor property namehelperDialect valuemysql/ property namereasonable valuetrue/ /plugin /plugins /configuration注意如果你同时使用了config-location和application.yml中的mybatis.configuration那么config-location指定的文件优先级更高application.yml中的同名配置可能会被忽略。建议只采用一种方式。4. Mapper接口与XML的“绑定魔术”Mybatis的核心思想是将接口和XML映射文件进行绑定。理解这个绑定机制是解决大部分“找不到语句”问题的关键。4.1 接口与XML的约定大于配置Mybatis Spring Boot Starter提供了自动扫描机制。你只需要满足以下约定Mapper接口这是一个普通的Java接口使用Mapper注解标记。这个注解可以被MapperScan替代在启动类上使用指定扫描的包路径这样包内的接口就不需要每个都加Mapper了。import org.apache.ibatis.annotations.Mapper; Mapper // 或者通过在启动类上加 MapperScan(com.xxx.mapper) public interface UserMapper { User selectById(Long id); ListUser selectAll(); int insert(User user); int update(User user); int deleteById(Long id); }XML映射文件其位置必须与mybatis.mapper-locations配置匹配。更重要的是XML文件的命名空间namespace必须是对应Mapper接口的全限定名。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.yourcompany.yourproject.mapper.UserMapper !-- 这里的idselectById 必须和接口中的方法名一致 -- select idselectById resultTypeUser SELECT * FROM user WHERE id #{id} /select !-- 其他SQL语句 -- /mapper绑定过程应用启动时Mybatis会扫描所有被Mapper标记的接口或MapperScan指定的包然后根据mapper-locations去找到对应的XML文件。它通过对比接口的全限定名和XML中namespace的值以及接口方法名和XML中SQL语句的id值来完成接口方法与SQL语句的绑定。4.2 常见绑定失败问题排查链当你遇到Invalid bound statement (not found)或BindingException时请按以下顺序排查这是我总结的“定式”检查一XML文件是否在正确路径确认mybatis.mapper-locations的值。确认XML文件是否真的被Maven/Gradle打包到了最终的jar/war包的对应路径下。可以解压生成的jar包查看BOOT-INF/classes/mapper/目录。检查二namespace和id是否完全匹配绝对匹配namespace必须是接口的全限定名包含包名一个字母都不能错。id必须和接口方法名完全一致包括大小写。使用IDE的“查找引用”功能点击接口方法名如果能跳转到XML中的对应select标签说明绑定成功。检查三是否发生了资源过滤问题Maven项目高频坑问题现象在IDE里运行正常打成jar包后运行报错。根因Maven在构建时默认只处理src/main/resources目录下的.properties和.xml文件。如果你的Mapper XML文件放在src/main/java目录下虽然不推荐但有人这么做或者使用了非标准目录就需要在pom.xml中配置资源过滤。解决方案在pom.xml的build部分添加resources resource directorysrc/main/resources/directory includes include**/*.xml/include /includes /resource !-- 如果你把xml放在java目录下需要额外添加 -- resource directorysrc/main/java/directory includes include**/*.xml/include /includes /resource /resources检查四是否有多数据源或自定义SqlSessionFactory如果你配置了多数据源或者手动定义了一个SqlSessionFactoryBean那么Starter的自动配置可能会失效。你需要确保在这些自定义配置中也正确设置了MapperLocations。5. 进阶配置与生产环境考量基础配置能让项目跑起来但要跑得稳、跑得好还需要一些进阶配置。5.1 多环境配置分离实际项目会有开发、测试、生产等多套环境数据库连接等信息肯定不同。Spring Boot的Profile机制是解决此问题的标准方案。application-dev.yml(开发环境)spring: datasource: url: jdbc:mysql://localhost:3306/dev_db username: dev_user password: dev_passapplication-prod.yml(生产环境)spring: datasource: url: jdbc:mysql://prod-db.cluster-xxx.rds.amazonaws.com:3306/prod_db username: ${DB_USERNAME} # 建议使用环境变量 password: ${DB_PASSWORD} hikari: maximum-pool-size: 50 # 生产环境连接池可以大一些application.yml(主配置设置激活的环境)spring: profiles: active: activatedProperties # Maven属性通常配合maven profile使用 # 或者直接指定 # spring.profiles.activedev通过启动参数--spring.profiles.activeprod来激活生产环境配置。5.2 集成PageHelper的详细配置如果你引入了PageHelper的Starter配置可以非常简洁大部分采用默认值即可。但了解关键配置有助于排查问题。在application.yml中pagehelper: helper-dialect: mysql # 指定数据库方言不指定时会自动检测 reasonable: true # 分页参数合理化。当pageNum0时设为1当pageNum总页数时设为总页数。 support-methods-arguments: true # 支持通过Mapper接口参数来传递分页参数 params: countcountSql # 配置count查询的SQL后缀使用心得PageHelper.startPage(pageNum, pageSize)必须紧挨着Mybatis查询方法之前调用。它通过一个ThreadLocal变量设置分页参数如果中间插入了其他数据库操作可能会导致参数被错误地应用到其他语句上。分页查询结束后可以用PageInfo对象来包装结果它能提供非常丰富的分页信息总页数、当前页、是否有下一页等。PageHelper.startPage(1, 10); ListUser userList userMapper.selectByExample(example); PageInfoUser pageInfo new PageInfo(userList);5.3 开启SQL日志打印调试利器在开发阶段查看Mybatis实际执行的SQL语句是调试的必备手段。有几种方式在mybatis-config.xml中配置见3.2节示例将logImpl设置为STDOUT_LOGGING会在控制台打印所有执行的SQL、参数和结果集行数。但格式比较简单。通过Logback/Log4j2配置推荐在application.yml中配置特定Mapper接口或包的日志级别为DEBUG。logging: level: com.yourcompany.yourproject.mapper: DEBUG # 将你的mapper包路径日志级别设为DEBUG这样配置后日志输出会更规范并且会包含完整的参数值格式更易读。这是我最常用的方式。6. 从配置到编码一个完整的极简示例让我们把上面的所有点串联起来创建一个最小可工作的例子。项目结构src/main/java/com/example/demo/ ├── DemoApplication.java (启动类) ├── entity/ │ └── User.java ├── mapper/ │ └── UserMapper.java └── service/ └── UserService.java src/main/resources/ ├── application.yml └── mapper/ └── UserMapper.xml1. 实体类 (User.java):package com.example.demo.entity; import java.time.LocalDateTime; public class User { private Long id; private String username; private String email; private LocalDateTime createTime; // getters and setters 省略建议使用Lombok的Data注解 }2. Mapper接口 (UserMapper.java):package com.example.demo.mapper; import com.example.demo.entity.User; import org.apache.ibatis.annotations.Mapper; import java.util.List; Mapper public interface UserMapper { User selectById(Long id); ListUser selectAll(); int insert(User user); }3. XML映射文件 (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 resultMap idBaseResultMap typeUser id columnid propertyid/ result columnusername propertyusername/ result columnemail propertyemail/ result columncreate_time propertycreateTime/ /resultMap select idselectById resultMapBaseResultMap SELECT id, username, email, create_time FROM user WHERE id #{id} /select select idselectAll resultMapBaseResultMap SELECT id, username, email, create_time FROM user /select insert idinsert parameterTypeUser useGeneratedKeystrue keyPropertyid INSERT INTO user (username, email, create_time) VALUES (#{username}, #{email}, #{createTime}) /insert /mapper4. 主配置文件 (application.yml):spring: datasource: url: jdbc:mysql://localhost:3306/test_db?useUnicodetruecharacterEncodingutf-8useSSLfalseserverTimezoneAsia/Shanghai username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.example.demo.entity configuration: map-underscore-to-camel-case: true logging: level: com.example.demo.mapper: DEBUG5. 启动类 (DemoApplication.java):package com.example.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }完成以上步骤后启动应用。如果控制台没有报错并且能看到数据源初始化和Mapper接口被注册的日志就说明Mybatis已经成功集成并配置好了。你可以编写一个简单的单元测试或Controller注入UserMapper并调用其方法同时观察控制台打印出的SQL日志来验证整个链路是否通畅。整个过程看似步骤不少但核心就是“依赖对、路径对、命名对”这三点。把这篇文章当作一个配置清单下次新项目搭建时对照着一步步来就能避开绝大多数初学者会踩的坑稳稳地迈出数据持久层的第一步。