MyBatis 到底能帮你省下多少 Java 数据库代码?

机器学习厨子
2025-12-28 23:10
阅读 1088

大家好,我是小张,一名 211 高校的计算机专业研究生。平时除了啃论文、调模型,我最大的爱好就是写技术博客——尤其是给刚入门的同学“搭梯子”。今天这篇教程,就是源于我当初学 Java 后端开发时踩过的一个大坑:怎么把 Java 对象存到数据库里?

那时候我以为要用纯 JDBC 手写一堆 PreparedStatementResultSet,结果代码又臭又长,还容易出错。后来导师一句话点醒我:“试试 MyBatis。” 从此,我的持久层代码清爽了至少一半。

所以,如果你也正在为 Java 操作数据库而头疼,这篇《MyBatis 基础教程》就是为你量身打造的。零基础也能跟着敲完一个完整示例,而且我会用最直白的语言解释每个概念,绝不堆术语。

注:虽然标题提到了“算法”,但 MyBatis 本身不涉及复杂算法——它更像一个“智能翻译官”,把 Java 方法自动转成 SQL 语句。不过,理解它的底层映射机制,其实也是一种轻量级的“对象-关系映射算法”思维。


一、MyBatis 是什么?为什么你需要它?

简单说:MyBatis 是一个 Java 持久层框架,专门用来简化数据库操作。

想象一下,你有一个 User 类:

public class User {
    private int id;
    private String name;
    private int age;
    // getter/setter 省略
}

你想把用户信息存进 MySQL 的 users 表。不用框架的话,得这样写:

String sql = "INSERT INTO users(name, age) VALUES (?, ?)";
PreparedStatement ps = connection.prepareStatement(sql);
ps.setString(1, user.getName());
ps.setInt(2, user.getAge());
ps.executeUpdate();

查数据更麻烦,还得手动把 ResultSet 一行行转成 Java 对象。

MyBatis 能让你只写接口和 SQL,剩下的它全包了。比如:

@Select("SELECT * FROM users WHERE id = #{id}")
User findById(int id);

是不是清爽多了?

💡 核心价值:MyBatis 把你从繁琐的 JDBC 模板代码中解放出来,让你专注业务逻辑和 SQL 本身。


二、环境准备:5 分钟搭建开发环境

我们用最主流的组合:IntelliJ IDEA + Maven + MySQL + JDK 8+

步骤 1:创建 Maven 项目

打开 IDEA → New Project → 选择 Maven → 不勾选 archetype → 项目名比如 mybatis-demo

步骤 2:添加依赖(pom.xml)

pom.xml<dependencies> 中加入:

<!-- MyBatis 核心 -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.13</version>
</dependency>

<!-- MySQL 驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.33</version>
</dependency>

<!-- 单元测试(可选但推荐) -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version>
    <scope>test</scope>
</dependency>

⚠️ 注意:如果你用的是 MySQL 8.x,驱动类名是 com.mysql.cj.jdbc.Driver,不是旧版的 com.mysql.jdbc.Driver

步骤 3:创建数据库和表

打开你的 MySQL 客户端(如 Navicat 或命令行),执行:

CREATE DATABASE mybatis_demo;
USE mybatis_demo;

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50) NOT NULL,
    age INT NOT NULL
);

步骤 4:配置 MyBatis(mybatis-config.xml)

src/main/resources 下新建 mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis_demo?useSSL=false&amp;serverTimezone=UTC"/>
        <property name="username" value="你的用户名"/>
        <property name="password" value="你的密码"/>
      </dataSource>
    </environment>
  </environments>
  
  <!-- 后面会在这里注册 Mapper -->
  <mappers>
    <mapper resource="mapper/UserMapper.xml"/>
  </mappers>
</configuration>

🔒 安全提示:生产环境中密码不要硬编码!这里仅为学习方便。


三、核心概念:3 个关键角色

MyBatis 的工作流程可以用一句话概括:Java 接口 → XML/注解 SQL → 自动映射结果

1. 实体类(Entity)

就是普通的 Java Bean,和数据库表字段对应。

// src/main/java/com/example/model/User.java
package com.example.model;

public class User {
    private int id;
    private String name;
    private int age;

    // 必须有无参构造函数(MyBatis 用反射创建对象)
    public User() {}

    // getter 和 setter
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }

    @Override
    public String toString() {
        return "User{id=" + id + ", name='" + name + "', age=" + age + "}";
    }
}

2. Mapper 接口

定义你要执行的数据库操作,不需要实现类

// src/main/java/com/example/mapper/UserMapper.java
package com.example.mapper;

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

public interface UserMapper {
    User findById(int id);
    List<User> findAll();
    void insert(User user);
    void update(User user);
    void delete(int id);
}

3. Mapper XML 文件(或注解)

告诉 MyBatis 每个方法对应的 SQL 是什么。

我们先用 XML 方式(更灵活,适合复杂 SQL):

<!-- src/main/resources/mapper/UserMapper.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper">

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

  <select id="findAll" resultType="com.example.model.User">
    SELECT * FROM users
  </select>

  <insert id="insert" parameterType="com.example.model.User">
    INSERT INTO users(name, age) VALUES (#{name}, #{age})
  </insert>

  <update id="update" parameterType="com.example.model.User">
    UPDATE users SET name = #{name}, age = #{age} WHERE id = #{id}
  </update>

  <delete id="delete" parameterType="int">
    DELETE FROM users WHERE id = #{id}
  </delete>

</mapper>

✅ 关键点:

  • namespace 必须是 Mapper 接口的全限定名
  • id 必须和接口方法名一致
  • #{} 是占位符,防止 SQL 注入

四、实战:完成一个完整的 CRUD 示例

现在,让我们把所有东西串起来!

第 1 步:编写工具类获取 SqlSession

// src/main/java/com/example/utils/SqlSessionFactoryUtils.java
package com.example.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;

public class SqlSessionFactoryUtils {
    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            throw new RuntimeException("加载 MyBatis 配置失败", e);
        }
    }

    public static SqlSessionFactory getSqlSessionFactory() {
        return sqlSessionFactory;
    }
}

第 2 步:编写测试代码

// src/test/java/com/example/AppTest.java
package com.example;

import com.example.mapper.UserMapper;
import com.example.model.User;
import com.example.utils.SqlSessionFactoryUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;

public class AppTest {

    @Test
    public void testCRUD() {
        SqlSession session = SqlSessionFactoryUtils.getSqlSessionFactory().openSession();
        UserMapper mapper = session.getMapper(UserMapper.class);

        // 1. 插入
        User user = new User();
        user.setName("张三");
        user.setAge(25);
        mapper.insert(user);
        session.commit(); // 别忘了提交!
        System.out.println("插入成功,ID: " + user.getId()); // 注意:此时 ID 还是 0!

        // 2. 查询所有
        List<User> users = mapper.findAll();
        for (User u : users) {
            System.out.println(u);
        }

        // 3. 更新
        if (!users.isEmpty()) {
            User first = users.get(0);
            first.setName("李四");
            first.setAge(26);
            mapper.update(first);
            session.commit();
        }

        // 4. 删除
        // mapper.delete(1);
        // session.commit();

        session.close();
    }
}

重要提醒:默认情况下,MyBatis 的 insert 不会自动回填主键 ID!如果你需要获取自增 ID,得在 <insert> 标签里加属性:

<insert id="insert" parameterType="com.example.model.User"
        useGeneratedKeys="true" keyProperty="id">
  INSERT INTO users(name, age) VALUES (#{name}, #{age})
</insert>

加上这行后,user.getId() 就能拿到数据库生成的 ID 了。


五、新手常见问题 & 解决方案

问题现象 可能原因 解决方案
BindingException: Invalid bound statement Mapper XML 的 namespace 或 id 写错 检查 namespace 是否等于接口全名,id 是否等于方法名
插入后 ID 为 0 没开启主键回填 <insert>useGeneratedKeys="true"keyProperty="id"
中文乱码 数据库连接没指定编码 在 JDBC URL 加 ?useUnicode=true&characterEncoding=utf8
找不到配置文件 resources 目录没被识别 确保 mybatis-config.xmlsrc/main/resources
事务没生效 忘记 session.commit() 所有写操作后必须调用 commit()

🧠 我当初学的时候,就因为没加 commit(),调试了整整一晚上,以为 MyBatis 有 bug……其实是自己漏了事务提交!


六、下一步学习建议

恭喜你,已经掌握了 MyBatis 的基础用法!但要真正用好它,建议你继续深入:

  1. 学习动态 SQL<if>, <choose>, <foreach> 等标签,让 SQL 更灵活。
  2. 掌握关联查询<resultMap> 处理一对一、一对多关系(比如用户-订单)。
  3. 集成 Spring Boot:实际项目中几乎都用 mybatis-spring-boot-starter
  4. 性能优化:了解一级/二级缓存、懒加载等机制。

🔍 避坑指南:不要一上来就学注解方式!XML 更适合团队协作和复杂 SQL。注解适合简单查询。


结语:让数据库操作回归本质

MyBatis 的哲学很简单:SQL 是你写的,对象是你定义的,框架只是桥梁。它不像 Hibernate 那样试图完全隐藏 SQL,而是让你掌控每一条语句——这对理解数据库原理、优化性能非常有帮助。

我写这篇教程,就是希望你能少走弯路。编程不是背语法,而是理解思想。当你下次看到 #{} 时,别只当它是占位符,想想它背后是如何防止 SQL 注入、如何做类型转换的——那才是真正的“算法”思维。

动手敲一遍代码吧!有问题欢迎在评论区留言,我会尽力解答。下期我们聊聊 MyBatis + Spring Boot 整合实战,敬请期待!

评论 0

最热最新
暂无评论
机器学习厨子Lv.1
0
影响力
0
文章
0
粉丝