Skip to content

MyBatis 快速入门

  从零开始搭建一个 MyBatis 项目,实现最简单的 CRUD 操作,体验 MyBatis 开发流程。

一、环境准备

技术栈:
  JDK 8+
  Maven 3.6+
  MySQL 5.7+
  MyBatis 3.5+

1.1 数据库建表

sql
CREATE DATABASE mybatis_demo DEFAULT CHARACTER SET utf8mb4;

USE mybatis_demo;

CREATE TABLE `user` (
    `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
    `name` VARCHAR(50) NOT NULL COMMENT '用户名',
    `age` INT COMMENT '年龄',
    `email` VARCHAR(100) COMMENT '邮箱',
    `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

-- 插入测试数据
INSERT INTO `user` (name, age, email) VALUES
('张三', 25, 'zhangsan@test.com'),
('李四', 30, 'lisi@test.com'),
('王五', 28, 'wangwu@test.com');

1.2 Maven 依赖

xml
<dependencies>
    <!-- MyBatis 核心 -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.15</version>
    </dependency>

    <!-- MySQL 驱动 -->
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.0.33</version>
    </dependency>

    <!-- 日志 -->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.4.14</version>
    </dependency>

    <!-- 测试 -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>

二、全局配置文件

mybatis-config.xml(放在 src/main/resources 下):

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

    <!-- 属性配置(可引入外部 properties 文件) -->
    <properties resource="db.properties"/>

    <!-- 全局设置 -->
    <settings>
        <!-- 启用驼峰命名自动映射:user_name → userName -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <!-- 打印 SQL 日志(使用 SLF4J) -->
        <setting name="logImpl" value="SLF4J"/>
        <!-- 延迟加载 -->
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>

    <!-- 类型别名 -->
    <typeAliases>
        <!-- 为 com.example.entity 包下所有类设置别名,即类名首字母小写 -->
        <package name="com.example.entity"/>
    </typeAliases>

    <!-- 环境配置 -->
    <environments default="development">
        <environment id="development">
            <!-- 事务管理器:JDBC 表示使用 JDBC 的事务管理 -->
            <transactionManager type="JDBC"/>
            <!-- 数据源:POOLED 表示使用 MyBatis 内置的连接池 -->
            <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=Asia/Shanghai"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <!-- 注册 Mapper 映射文件 -->
    <mappers>
        <!-- 方式一:逐个注册 XML -->
        <!-- <mapper resource="mapper/UserMapper.xml"/> -->

        <!-- 方式二:扫描包(推荐) -->
        <package name="com.example.mapper"/>
    </mappers>

</configuration>

注意: mappers<package> 扫描时,要求 XML 文件和接口在同一包路径下(resources 目录中要建相同的包结构)。

三、编写实体类与 Mapper

3.1 实体类

java
package com.example.entity;

public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
    private Date createTime;

    // 必须有无参构造器
    public User() {}

    // getter / setter(省略)
    // toString()
}

3.2 Mapper 接口

java
package com.example.mapper;

import com.example.entity.User;

public interface UserMapper {
    User selectById(Long id);
    List<User> selectAll();
    int insert(User user);
    int update(User user);
    int deleteById(Long id);
    List<User> selectByName(String name);
}

3.3 Mapper XML

UserMapper.xml(放在 resources/com/example/mapper/ 下):

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">

<!-- namespace = 接口全限定名 -->
<mapper namespace="com.example.mapper.UserMapper">

    <!-- 查询单个 -->
    <select id="selectById" resultType="com.example.entity.User">
        SELECT id, name, age, email, create_time
        FROM user
        WHERE id = #{id}
    </select>

    <!-- 查询全部 -->
    <select id="selectAll" resultType="com.example.entity.User">
        SELECT * FROM user
    </select>

    <!-- 新增(获取自增主键) -->
    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO user (name, age, email)
        VALUES (#{name}, #{age}, #{email})
    </insert>

    <!-- 修改 -->
    <update id="update">
        UPDATE user
        SET name = #{name}, age = #{age}, email = #{email}
        WHERE id = #{id}
    </update>

    <!-- 删除 -->
    <delete id="deleteById">
        DELETE FROM user WHERE id = #{id}
    </delete>

    <!-- 模糊查询 -->
    <select id="selectByName" resultType="com.example.entity.User">
        SELECT * FROM user
        WHERE name LIKE CONCAT('%', #{name}, '%')
    </select>

</mapper>

四、编写测试

java
package com.example;

import com.example.entity.User;
import com.example.mapper.UserMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.InputStream;
import java.util.List;

public class UserMapperTest {

    private SqlSessionFactory sqlSessionFactory;
    private SqlSession sqlSession;
    private UserMapper userMapper;

    @Before
    public void setUp() throws Exception {
        // 1. 加载全局配置文件
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        // 2. 创建 SqlSessionFactory
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 3. 获取 SqlSession
        sqlSession = sqlSessionFactory.openSession();
        // 4. 获取 Mapper 代理对象
        userMapper = sqlSession.getMapper(UserMapper.class);
    }

    @After
    public void tearDown() {
        if (sqlSession != null) {
            sqlSession.close();
        }
    }

    @Test
    public void testSelectById() {
        User user = userMapper.selectById(1L);
        System.out.println(user);
    }

    @Test
    public void testSelectAll() {
        List<User> users = userMapper.selectAll();
        users.forEach(System.out::println);
    }

    @Test
    public void testInsert() {
        User user = new User();
        user.setName("赵六");
        user.setAge(22);
        user.setEmail("zhaoliu@test.com");
        int rows = userMapper.insert(user);
        System.out.println("插入成功,影响行数:" + rows);
        System.out.println("自增主键:" + user.getId());
        sqlSession.commit();  // 增删改必须提交!
    }

    @Test
    public void testUpdate() {
        User user = userMapper.selectById(1L);
        user.setAge(26);
        int rows = userMapper.update(user);
        System.out.println("更新成功,影响行数:" + rows);
        sqlSession.commit();
    }

    @Test
    public void testDelete() {
        int rows = userMapper.deleteById(4L);
        System.out.println("删除成功,影响行数:" + rows);
        sqlSession.commit();
    }

    @Test
    public void testSelectByName() {
        List<User> users = userMapper.selectByName("三");
        users.forEach(System.out::println);
    }
}

五、开发流程总结

MyBatis 开发步骤(七步走):

  ① 建表                      → 数据库建表
  ② 加依赖                    → pom.xml 引入 mybatis + 驱动
  ③ 写配置                    → mybatis-config.xml
  ④ 写实体                    → Entity 类(POJO)
  ⑤ 写接口                    → Mapper 接口
  ⑥ 写映射                    → Mapper.xml(SQL 映射)
  ⑦ 写测试                    → 获取 SqlSession → 执行操作

速记口诀:
  表→依赖→配置→实体→接口→映射→测试

六、关键注意事项

① 增删改必须手动提交事务
  sqlSession.commit();  // 否则不会持久化到数据库
  或者使用 openSession(true) 开启自动提交

② Mapper XML 必须和接口在同一路径
  否则需要逐个配置 <mapper resource="..."/>

③ 实体类必须有 无参构造器
  否则 MyBatis 反射创建对象时报错

④ #{ } 和 ${ } 的区别
  #{} → 预编译占位符(防 SQL 注入)→ 推荐
  ${} → 字符串拼接(有 SQL 注入风险)→ 仅用于动态表名/列名

⑤ namespace 必须等于接口全限定名
  否则无法绑定

七、面试要点

问题答案要点
开发步骤?建表→依赖→配置→实体→接口→映射→测试
增删改为什么需要 commit?默认手动提交,openSession() 不自动提交
#{ } 和 ${ } 的区别?#{} 预编译防注入,${} 字符串替换有风险
如何获取自增主键?useGeneratedKeys="true" + keyProperty="id"