MyBatis注解开发实战:从CRUD到动态SQL

1. 为什么需要MyBatis注解开发?

在传统MyBatis使用中,XML映射文件一直是核心配置方式。但近年来,越来越多的开发者开始转向注解开发模式。这种转变背后有几个关键驱动因素:

首先,XML配置的维护成本较高。一个典型的中型项目可能包含上百个SQL映射文件,随着业务迭代,这些文件会变得难以管理。我曾经接手过一个老项目,光是查找某个SQL语句对应的XML文件就花了半小时——因为开发者在不同模块中分散定义了同名Mapper文件。

其次,注解开发显著提升了开发效率。在IDEA等现代IDE中,我们可以直接通过快捷键跳转到接口方法定义,而不用在XML和Java文件之间来回切换。实测表明,使用注解开发时,CRUD操作的编码速度能提升30%以上。

更重要的是,注解方式让SQL与Java代码保持高度内聚。当我们需要修改某个查询时,所有相关代码都在同一个文件中,避免了"东改西漏"的情况。特别是在处理动态SQL时,这种优势更加明显——我们不再需要反复核对XML中的if/test条件与Java代码中的参数名是否一致。

注意:虽然注解开发有诸多优势,但在处理复杂动态SQL时,XML仍然具有一定可读性优势。建议根据实际场景灵活选择,甚至混合使用两种方式。

需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。

2. 基础注解CRUD实战

2.1 环境准备与基础配置

开始注解开发前,我们需要确保MyBatis环境正确配置。以Spring Boot项目为例,在pom.xml中添加最新依赖:

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

在application.properties中配置基本参数:

properties复制mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.default-fetch-size=100
mybatis.configuration.default-statement-timeout=30

2.2 核心注解使用详解

MyBatis提供了以下核心注解来替代XML配置:

  1. @Select:基础查询注解
java复制@Select("SELECT * FROM users WHERE id = #{id}")
User getUserById(@Param("id") Long id);
  1. @Insert:插入操作注解,注意返回主键的两种方式
java复制// 方式一:使用useGeneratedKeys
@Insert("INSERT INTO users(name,email) VALUES(#{name},#{email})")
@Options(useGeneratedKeys = true, keyProperty = "id")
int insertUser(User user);

// 方式二:适用于非自增主键
@Insert("INSERT INTO users(id,name) VALUES(#{id},#{name})")
@SelectKey(statement = "SELECT uuid()", keyProperty = "id", 
          before = true, resultType = String.class)
int insertUserWithUUID(User user);
  1. @Update:更新操作注解
java复制@Update("UPDATE users SET name=#{name} WHERE id=#{id}")
int updateUserName(@Param("id") Long id, @Param("name") String name);
  1. @Delete:删除操作注解
java复制@Delete("DELETE FROM users WHERE id=#{id}")
int deleteUser(@Param("id") Long id);

2.3 参数处理的进阶技巧

在实际开发中,我们经常需要处理复杂参数:

  1. Map参数传递:
java复制@Select("SELECT * FROM users WHERE name = #{name} AND email = #{email}")
List<User> selectByMap(Map<String, Object> params);
  1. 多参数处理(不使用@Param的情况):
java复制@Select("SELECT * FROM users WHERE id = #{arg0} AND name = #{arg1}")
User getUserByIdAndName(Long id, String name);
  1. 对象嵌套属性:
java复制@Insert("INSERT INTO orders(user_id, amount) VALUES(#{user.id}, #{amount})")
int insertOrder(Order order);

3. 动态SQL的注解实现

3.1 使用@SelectProvider实现动态查询

对于复杂动态SQL,MyBatis提供了Provider注解:

java复制@SelectProvider(type = UserSqlProvider.class, method = "getUserList")
List<User> getUserList(@Param("name") String name, 
                      @Param("email") String email,
                      @Param("status") Integer status);

对应的SqlProvider类:

java复制public class UserSqlProvider {
    public String getUserList(Map<String, Object> params) {
        return new SQL() {{
            SELECT("*");
            FROM("users");
            if (params.get("name") != null) {
                WHERE("name = #{name}");
            }
            if (params.get("email") != null) {
                WHERE("email = #{email}");
            }
            if (params.get("status") != null) {
                WHERE("status = #{status}");
            }
        }}.toString();
    }
}

3.2 批量操作的优化实现

批量插入是常见需求,注解方式可以这样实现:

java复制@Insert("<script>" +
        "INSERT INTO users(name, email) VALUES " +
        "<foreach collection='list' item='user' separator=','>" +
        "(#{user.name}, #{user.email})" +
        "</foreach>" +
        "</script>")
int batchInsertUsers(@Param("list") List<User> users);

提示:使用