Spring Boot 集成 MyBatis 操作数据库实战
为什么要引入 MyBatis?
在纯 JDBC 开发中,我们往往要面对一堆重复且繁琐的样板代码:手动管理连接池、编写带占位符的 SQL、逐行绑定参数、处理 ResultSet 结果集映射,还得在 finally 块里确保资源关闭。这些不仅效率低,还容易引发资源泄露。
MyBatis 作为持久层框架,核心价值在于解耦和简化。它把 SQL 从 Java 代码里剥离出来,自动完成结果集到对象的映射,让开发者能更专注于业务逻辑本身。
环境搭建与核心配置
依赖引入
在 pom.xml 中加入 MyBatis Starter 和 MySQL 驱动即可。注意根据项目实际情况调整版本:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
开启 SQL 日志
调试时,实时看到生成的 SQL 非常关键。在配置文件中加上这行,控制台就会打印执行语句:
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
开发模式:注解与 XML
MyBatis 主要提供两种开发方式,实际项目中通常混合使用。
1. 注解模式(适合简单 CRUD)
对于单表查询或简单的增删改,直接在 Mapper 接口上加注解最省事。比如查单个用户,或者插入后拿回自增 ID:
@Mapper
public interface UserInfoMapper {
// 根据 ID 查询用户
@Select("select * from user_info where id = #{id}")
UserInfo queryById(Integer id);
// 插入并返回自增主键 ID
@Insert("insert into user_info (username, password) values (#{username}, #{password})")
@Options(useGeneratedKeys = true, keyProperty = "id")
Integer insert(UserInfo userInfo);
}
这里用 @Options 是为了告诉 MyBatis 把数据库生成的主键回填到 userInfo 对象的 id 字段里,不然插入完你也不知道这条数据的主键是多少。
2. XML 映射模式(适合复杂业务)
一旦涉及多表关联、动态 SQL 或者复杂的映射关系,XML 就比注解灵活多了。它能更好地维护 SQL 结构,方便后续优化。
<mapper namespace="com.example.demo.mapper.UserInfoXMlMapper">
<resultMap id="BaseMap" type="com.example.demo.model.UserInfo">
<id column="id" property="id"></id>
<result column="delete_flag" property="deleteFlag"></result>
</resultMap>
<select id="queryAllUser" resultMap="BaseMap">
select * from user_info
</select>
</mapper>
#{} 与 ${} 的本质区别
这是面试必问,也是生产安全的关键点。虽然它们都能传参,但底层机制完全不同。
| 特性 | #{} (预编译) | ${} (字符串替换) |
|---|---|---|
| 工作原理 | 使用 ? 占位符,JDBC 预编译 | 直接拼接字符串 |
| 安全性 | 防止 SQL 注入 | 存在 SQL 注入风险 |
| 引号处理 | 自动添加字符串引号 | 不会自动添加引号 |
| 性能 | 高,可复用执行计划 | 较低,每次重新解析 |
除非万不得已(比如动态排序字段),否则请优先使用 #{}。如果用了 ${} 且参数来自用户输入,那你的系统随时可能被注入攻击。
多表关联查询进阶
MyBatis 处理联表的核心在于通过映射关系把结果集组装成对象。比如查询文章及其作者信息:
@Select("SELECT ta.id, ta.title, tb.username FROM articleinfo ta LEFT JOIN user_info tb ON ta.uid = tb.id WHERE ta.id = #{id}")
ArticleInfo queryUserByUid(Integer id);
配合好 <resultMap>,就能把分散在不同表的字段正确填充到实体类的不同属性上。
企业级规范与优化建议
1. 数据库命名规范
保持统一很重要。推荐表名和字段名全小写,单词间用下划线分隔(如 user_info)。同时,在 yml 中开启驼峰转换,这样 Java 里的 userName 就能自动对应数据库的 user_name:
mybatis:
configuration:
map-underscore-to-camel-case: true
2. Druid 连接池配置
生产环境别用默认的 HikariCP 凑合,建议引入阿里巴巴的 Druid 连接池。它不仅性能好,还能提供强大的监控功能,方便排查慢 SQL 问题。
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
<version>1.2.21</version>
</dependency>
总结
MyBatis 通过灵活的配置和映射机制,极大提升了 Java 持久层的开发效率。在实际工作中,建议根据业务复杂度选择注解或 XML 模式,并始终将安全性放在首位,优先使用预编译参数。

