MyBatis基础教程:Java持久层框架入门实战分享

韩雨泽
2025-06-18 01:38
阅读 529

开篇:为什么选择MyBatis?

开篇:为什么选择MyBatis?

还记得我刚入职那会儿,公司项目刚开始从Spring JDBC迁移到一个更灵活的持久层框架。那时候我对各种ORM框架都一知半解,Hibernate、JPA、MyBatis这些词听得耳朵都快起茧了。最后选型MyBatis的原因很实际——我们需要在灵活性和开发效率之间找一个平衡点。

Hibernate确实功能强大,但封装太深;而JPA又偏重于标准规范,对复杂SQL支持有限。最终我们决定采用MyBatis,一款轻量、灵活、适合国内团队使用的持久层框架。

这篇技术文章,就是我想结合自己这几年用MyBatis做项目的经验,写一份“够用、实用、能上手”的入门教程。不是那种官方文档式的东西,而是从真实项目的角度出发,讲清楚为什么要这么用、可能踩什么坑,以及如何高效地搭建起自己的DAO层逻辑。


问题描述:传统数据库操作方式的痛点

问题描述:传统数据库操作方式的痛点

在我参与的第一个项目中,我们一开始是直接使用JDBC来操作数据库的。说实话,那段日子真是噩梦。

举个简单的例子:我们要根据用户ID查询用户信息,然后更新他的手机号码。用原生JDBC写的话,得手动处理连接、Statement、ResultSet这些底层细节,代码冗长不说,还容易出错。比如忘关连接啊、参数绑定错了顺序啊,这类低级错误在初期频繁出现。

再加上随着业务增长,SQL越来越复杂,拼接字符串也变得难维护。特别是在做动态条件查询(例如带筛选条件的列表接口)时,用if-else拼字符串简直是在折磨人。

这时候我们开始思考:有没有一种方式既能保留SQL的控制权,又能屏蔽掉底层JDBC的各种琐事?答案当然是肯定的:MyBatis


解决方案:为什么选择MyBatis?

解决方案:为什么选择MyBatis?

我们最终选择了MyBatis,主要原因有以下几点:

  1. 灵活性高:不像Hibernate那样自动帮你生成SQL,MyBatis让我们完全掌控SQL的编写;
  2. 轻量级易集成:它和Spring Boot整合起来非常方便;
  3. 性能友好:没有复杂的代理机制,运行效率更高;
  4. 适合中国开发者习惯:很多后端系统在国内都是以MySQL为核心,MyBatis正好契合这种需求。

接下来我们就通过一个简单的用户管理模块,来看看如何快速上手MyBatis。


代码实践:MyBatis的基础使用步骤

1. 初始化Spring Boot项目

首先创建一个基本的Spring Boot项目,在pom.xml中加入以下依赖:

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>3.0.3</version>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

如果你还在用旧版本,需要注意升级到兼容Spring Boot 3.x的新版本。


2. 配置数据源和MyBatis

配置文件application.yml内容如下:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/demo_db?useSSL=false&serverTimezone=UTC
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis:
  mapper-locations: classpath:mapper/**/*.xml
  type-aliases-package: com.example.model

这里要注意mapper-locations的路径是否正确,否则MyBatis会找不到XML映射文件。


3. 定义Model实体类

比如User类:

package com.example.model;

public class User {
    private Long id;
    private String name;
    private String phone;
    private String email;
    
    // Getters & Setters
}

记得加上getter/setter方法,这样MyBatis才能正确映射字段。


4. 编写Mapper接口

package com.example.mapper;

import com.example.model.User;
import java.util.List;

public interface UserMapper {
    User selectById(Long id);
    
    List<User> selectByCondition(String keyword);

    int insert(User user);
    
    int update(User user);
}

这就是DAO接口,方法名对应XML中SQL语句的id。


5. 写XML映射文件

创建src/main/resources/mapper/UserMapper.xml,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.example.mapper.UserMapper">
    <select id="selectById" resultType="com.example.model.User">
        SELECT * FROM users WHERE id = #{id}
    </select>

    <select id="selectByCondition" resultType="com.example.model.User">
        SELECT * FROM users
        <where>
            <if test="keyword != null and keyword != ''">
                AND (name LIKE CONCAT('%', #{keyword}, '%')
                OR phone LIKE CONCAT('%', #{keyword}, '%'))
            </if>
        </where>
    </select>

    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO users (name, phone, email)
        VALUES (#{name}, #{phone}, #{email})
    </insert>

    <update id="update">
        UPDATE users
        SET name = #{name},
            phone = #{phone},
            email = #{email}
        WHERE id = #{id}
    </update>
</mapper>

可以看到,MyBatis的XML提供了强大的标签,如<if><choose>等,非常适合构建动态SQL。


6. 在Service中注入并使用

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public User getUserById(Long id) {
        return userMapper.selectById(id);
    }

    public List<User> searchUsers(String keyword) {
        return userMapper.selectByCondition(keyword);
    }
}

整个结构清晰、易于维护,而且我们依然可以自由调整每一条SQL。


踩坑经验:那些年我们在MyBatis上栽过的坑

数据库设计模型-1

坑一:参数传递方式搞错导致SQL执行异常

比如下面这行代码:

List<User> selectByCondition(String keyword);

而在XML中的if条件是:

<if test="keyword != null and keyword != ''">

没问题对吧?但如果是一个多参数的接口,比如我要传入两个字段怎么办?如果不用@Param指定参数名,MyBatis默认会按顺序取名为arg0、arg1,这时test判断就出错了。

正确做法:

List<User> selectByMultiCondition(@Param("name") String name, @Param("phone") String phone);

然后XML里就可以用:

<if test="name != null">AND name like #{name}</if>
<if test="phone != null">AND phone like #{phone}</if>

这个细节不注意,很容易在调试阶段浪费大量时间。


坑二:自动生成主键没配置好,导致插入失败

在写insert语句的时候,记得添加:

<insert id="insert" useGeneratedKeys="true" keyProperty="id">

否则插入成功后你根本不知道这条记录的实际ID是多少。对于需要返回id的场景(比如后续还要保存关联数据),这就成了一个致命bug。


坑三:XML路径配置错误,导致无法加载映射文件

很多人刚上手MyBatis的时候都会遇到这个问题:提示“No such SQL mapping found”,排查半天发现是因为mapper-locations路径写错了。

建议大家统一放在resources目录下,并且按模块归类,比如:

resources/
└── mapper/
    └── user/
        └── UserMapper.xml

对应的YAML配置为:

mybatis:
  mapper-locations: classpath:mapper/**/*Mapper.xml

效果总结:引入MyBatis后的收益

项目上线后,我们的DAO层代码明显整洁了许多,主要收获有:

  • 开发效率提升:减少了重复的JDBC样板代码,提升了70%左右的开发速度;
  • 可维护性增强:SQL和业务逻辑分离,修改起来更容易;
  • 性能优化空间更大:因为SQL可控,我们可以针对性地进行索引优化或拆分复杂查询;
  • 线上问题定位更快捷:可以通过日志输出查看完整的SQL语句,便于排查慢查询等问题。

特别是在线上遇到慢查询时,我可以直接把SQL拿到数据库工具中执行分析,而不是像Hibernate那样只能看HQL。


经验分享:给新手的几点建议

负载均衡配置-2

✅ 使用注解还是XML?我建议优先用XML

虽然MyBatis支持使用注解写SQL,但在实际项目中我更推荐使用XML方式。理由是XML结构清晰,尤其在面对复杂SQL、动态条件较多的情况下,阅读和维护成本更低。

✅ 动态SQL尽量模块化,避免过于臃肿

比如 <if><choose>标签不要嵌套太多,可以用 <include> 引入公共片段,保持每个SQL块职责单一。

✅ 日志一定要开起来!

调试时强烈建议开启MyBatis的日志输出,比如通过logback配置打印SQL语句:

logging:
  level:
    com.example.mapper: debug

这样可以在控制台看到完整SQL和参数,对排查问题帮助很大。


技术趋势与生产环境考虑

与Spring Boot的深度整合

目前MyBatis与Spring Boot已经高度集成,几乎做到了即插即用。配合PageHelper可以实现分页查询,结合Druid做数据库监控也很方便。

多数据源处理(进阶)

如果你有多个数据源,比如读写分离或者不同业务库的情况,可以使用dynamic-datasource-spring-boot-starter来管理。这在金融或电商类系统中比较常见。

数据库设计的一些思考

  • 表结构要合理设计索引:MyBatis本身不关心索引,但写出来的SQL如果没有命中索引,就会拖慢整体性能。
  • 避免大表JOIN过多:适当拆分数据模型,减少单次SQL的复杂度。

小结一下

这篇文章是我结合几个项目的真实经历写成的,希望能让刚接触MyBatis的同学少走一些弯路。总的来说,MyBatis作为Java Web领域最主流的持久层框架之一,它简单易用、性能可控、扩展性强,尤其是在微服务架构下,它是实现轻量级持久化的理想选择。

当然,任何技术都有它的适用场景,我也不是说MyBatis就一定比别的框架好。比如在某些强ORM需求、快速原型搭建的场景中,JPA或Hibernate可能更合适。

但如果你追求对SQL的完全掌控,同时又不想陷入原始JDBC的泥潭,那么MyBatis绝对值得你在项目中试一试。


如果你有任何MyBatis相关的问题,欢迎留言交流。我在工作中也经常被同事拉去帮忙“看看这段SQL为啥查不到”,咱们一起成长、互帮互助 💪。

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝