Skip to content

MyBatis 简介

什么是MyBatis?

MyBatis是一款优秀的持久层框架,它支持自定义SQL、存储过程以及高级映射。MyBatis免除了几乎所有的JDBC代码以及设置参数和获取结果集的工作。

为什么选择MyBatis?

优点

  • 灵活性高:支持自定义SQL,可以进行复杂查询优化
  • SQL与代码分离:SQL语句写在XML或注解中,便于维护
  • 消除JDBC冗余代码:自动处理连接、预编译、结果映射
  • 强大的结果映射:支持复杂的对象关系映射
  • 动态SQL:根据条件动态生成SQL
  • 缓存支持:一级缓存和二级缓存

与JPA/Hibernate对比

  • MyBatis更灵活,适合复杂查询和性能优化
  • JPA更简单,适合标准CRUD操作
  • MyBatis学习曲线相对平缓

核心组件

1. SqlSessionFactory

MyBatis的核心,用于创建SqlSession。

java
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = 
    new SqlSessionFactoryBuilder().build(inputStream);

2. SqlSession

执行SQL命令、获取映射器、管理事务的接口。

java
try (SqlSession session = sqlSessionFactory.openSession()) {
    UserMapper mapper = session.getMapper(UserMapper.class);
    User user = mapper.selectById(1L);
}

3. Mapper接口

定义SQL操作的接口。

java
public interface UserMapper {
    User selectById(Long id);
    List<User> selectAll();
    int insert(User user);
    int update(User user);
    int delete(Long id);
}

快速开始

1. 添加依赖

Maven:

xml
<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>
</dependency>

2. 配置数据源

application.yml:

yaml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf-8
    username: root
    password: password
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.example.domain
  configuration:
    map-underscore-to-camel-case: true # 下划线转驼峰
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # SQL日志

3. 创建实体类

java
@Data
public class User {
    private Long id;
    private String username;
    private String email;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
}

4. 创建Mapper接口

java
@Mapper
public interface UserMapper {
    User selectById(Long id);
    List<User> selectAll();
    int insert(User user);
    int update(User user);
    int delete(Long id);
}

5. 创建Mapper XML

resources/mapper/UserMapper.xml:

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="User">
        SELECT * FROM user WHERE id = #{id}
    </select>
    
    <select id="selectAll" resultType="User">
        SELECT * FROM user
    </select>
    
    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO user (username, email, create_time)
        VALUES (#{username}, #{email}, #{createTime})
    </insert>
    
    <update id="update">
        UPDATE user
        SET username = #{username},
            email = #{email},
            update_time = #{updateTime}
        WHERE id = #{id}
    </update>
    
    <delete id="delete">
        DELETE FROM user WHERE id = #{id}
    </delete>
    
</mapper>

6. 使用Mapper

java
@Service
public class UserService {
    
    @Autowired
    private UserMapper userMapper;
    
    public User getUserById(Long id) {
        return userMapper.selectById(id);
    }
    
    public List<User> getAllUsers() {
        return userMapper.selectAll();
    }
    
    public void createUser(User user) {
        user.setCreateTime(LocalDateTime.now());
        userMapper.insert(user);
    }
}

基本CRUD操作

Insert

xml
<!-- 简单插入 -->
<insert id="insert">
    INSERT INTO user (username, email)
    VALUES (#{username}, #{email})
</insert>

<!-- 返回自增主键 -->
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO user (username, email)
    VALUES (#{username}, #{email})
</insert>

<!-- 批量插入 -->
<insert id="insertBatch">
    INSERT INTO user (username, email)
    VALUES
    <foreach collection="list" item="user" separator=",">
        (#{user.username}, #{user.email})
    </foreach>
</insert>

Select

xml
<!-- 根据ID查询 -->
<select id="selectById" resultType="User">
    SELECT * FROM user WHERE id = #{id}
</select>

<!-- 查询所有 -->
<select id="selectAll" resultType="User">
    SELECT * FROM user
</select>

<!-- 条件查询 -->
<select id="selectByCondition" resultType="User">
    SELECT * FROM user
    WHERE username = #{username}
    AND email = #{email}
</select>

<!-- 模糊查询 -->
<select id="selectByKeyword" resultType="User">
    SELECT * FROM user
    WHERE username LIKE CONCAT('%', #{keyword}, '%')
</select>

Update

xml
<!-- 更新 -->
<update id="update">
    UPDATE user
    SET username = #{username},
        email = #{email},
        update_time = NOW()
    WHERE id = #{id}
</update>

<!-- 选择性更新 -->
<update id="updateSelective">
    UPDATE user
    <set>
        <if test="username != null">username = #{username},</if>
        <if test="email != null">email = #{email},</if>
        update_time = NOW()
    </set>
    WHERE id = #{id}
</update>

Delete

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

<!-- 批量删除 -->
<delete id="deleteBatch">
    DELETE FROM user WHERE id IN
    <foreach collection="ids" item="id" open="(" separator="," close=")">
        #{id}
    </foreach>
</delete>

参数传递

单个参数

java
User selectById(Long id);
xml
<select id="selectById" resultType="User">
    SELECT * FROM user WHERE id = #{id}
</select>

多个参数

方式1:使用@Param注解

java
List<User> selectByUsernameAndEmail(
    @Param("username") String username,
    @Param("email") String email
);
xml
<select id="selectByUsernameAndEmail" resultType="User">
    SELECT * FROM user
    WHERE username = #{username}
    AND email = #{email}
</select>

方式2:使用Map

java
List<User> selectByMap(Map<String, Object> params);
xml
<select id="selectByMap" resultType="User">
    SELECT * FROM user
    WHERE username = #{username}
    AND email = #{email}
</select>

方式3:使用对象

java
List<User> selectByCondition(UserQuery query);
xml
<select id="selectByCondition" resultType="User">
    SELECT * FROM user
    WHERE username = #{username}
    AND email = #{email}
</select>

结果映射

自动映射

xml
<!-- 字段名与属性名一致时自动映射 -->
<select id="selectById" resultType="User">
    SELECT id, username, email FROM user WHERE id = #{id}
</select>

手动映射 - resultMap

xml
<resultMap id="userResultMap" type="User">
    <id property="id" column="user_id"/>
    <result property="username" column="user_name"/>
    <result property="email" column="user_email"/>
    <result property="createTime" column="create_time"/>
</resultMap>

<select id="selectById" resultMap="userResultMap">
    SELECT user_id, user_name, user_email, create_time
    FROM user
    WHERE user_id = #{id}
</select>

关联查询 - 一对一

java
@Data
public class User {
    private Long id;
    private String username;
    private UserProfile profile; // 一对一
}

@Data
public class UserProfile {
    private Long id;
    private Long userId;
    private String avatar;
    private String bio;
}
xml
<resultMap id="userWithProfileMap" type="User">
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <association property="profile" javaType="UserProfile">
        <id property="id" column="profile_id"/>
        <result property="userId" column="user_id"/>
        <result property="avatar" column="avatar"/>
        <result property="bio" column="bio"/>
    </association>
</resultMap>

<select id="selectUserWithProfile" resultMap="userWithProfileMap">
    SELECT u.id, u.username,
           p.id as profile_id, p.user_id, p.avatar, p.bio
    FROM user u
    LEFT JOIN user_profile p ON u.id = p.user_id
    WHERE u.id = #{id}
</select>

关联查询 - 一对多

java
@Data
public class User {
    private Long id;
    private String username;
    private List<Order> orders; // 一对多
}

@Data
public class Order {
    private Long id;
    private Long userId;
    private BigDecimal amount;
}
xml
<resultMap id="userWithOrdersMap" type="User">
    <id property="id" column="id"/>
    <result property="username" column="username"/>
    <collection property="orders" ofType="Order">
        <id property="id" column="order_id"/>
        <result property="userId" column="user_id"/>
        <result property="amount" column="amount"/>
    </collection>
</resultMap>

<select id="selectUserWithOrders" resultMap="userWithOrdersMap">
    SELECT u.id, u.username,
           o.id as order_id, o.user_id, o.amount
    FROM user u
    LEFT JOIN `order` o ON u.id = o.user_id
    WHERE u.id = #{id}
</select>

注解方式

除了XML配置,MyBatis也支持注解方式:

java
@Mapper
public interface UserMapper {
    
    @Select("SELECT * FROM user WHERE id = #{id}")
    User selectById(Long id);
    
    @Select("SELECT * FROM user")
    List<User> selectAll();
    
    @Insert("INSERT INTO user (username, email) VALUES (#{username}, #{email})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insert(User user);
    
    @Update("UPDATE user SET username = #{username}, email = #{email} WHERE id = #{id}")
    int update(User user);
    
    @Delete("DELETE FROM user WHERE id = #{id}")
    int delete(Long id);
    
    @Select("SELECT * FROM user WHERE username LIKE CONCAT('%', #{keyword}, '%')")
    List<User> selectByKeyword(String keyword);
}

配置扫描

方式1:@MapperScan

java
@SpringBootApplication
@MapperScan("com.example.mapper")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

方式2:@Mapper注解

java
@Mapper
public interface UserMapper {
    // ...
}

下一步