本文是介绍如何用注解替代 XML 配置文件,完成 SQL 映射、结果集映射以及二级缓存的配置。


一、为什么要用注解开发

XML 开发需要维护大量 mapper.xml 文件,对于简单的 CRUD 操作略显繁琐。注解开发把 SQL 直接写在接口方法上,减少文件数量,代码更集中。

两种方式对比:

XML 开发注解开发
SQL 位置mapper.xml 文件接口方法上的注解
结果映射<resultMap>@Results + @Result
注册方式resource="mapper/StudentMapper.xml"class="com.demo.mapper.StudentMapper"
适用场景复杂 SQL、动态 SQL简单 CRUD

二、核心注解说明

注解对应 XML 标签作用
@Select<select>查询 SQL
@Insert<insert>插入 SQL
@Update<update>更新 SQL
@Delete<delete>删除 SQL
@Results<resultMap>声明结果集映射
@Result<result>单个字段映射
@ResultMapresultMap="xxx"复用已声明的 resultMap
@CacheNamespace<cache/>开启二级缓存

三、基本用法

XML 写法 vs 注解写法

XML:

<select id="findAll" resultMap="userMap">
    select * from user
</select>

<resultMap id="userMap" type="User">
    <result property="id"       column="id"/>
    <result property="username" column="username"/>
    <result property="birthday" column="birthday"/>
    <result property="sex"      column="sex"/>
    <result property="address"  column="address"/>
</resultMap>

注解:

@Select("select * from user")
@Results(id = "userMap", value = {
    @Result(property = "id",       column = "id"),
    @Result(property = "username", column = "username"),
    @Result(property = "birthday", column = "birthday"),
    @Result(property = "sex",      column = "sex"),
    @Result(property = "address",  column = "address")
})
List<User> findAll();

什么时候可以省略 @Results
当 Java 属性名和数据库列名完全一致时,MyBatis 可以自动映射,无需声明。只有字段名不一致时才需要 @Results

复用 ResultMap

@Resultsid 属性可以给这个映射起名字,在其他方法上通过 @ResultMap 复用:

@Select("select * from user where id = #{id}")
@ResultMap("userMap")   // 复用上面声明的 userMap
User findById(int id);

四、完整 CRUD 示例

public interface UserDao {

    // 查询所有
    @Select("select * from user")
    @Results(id = "userMap", value = {
        @Result(property = "id",       column = "id",       id = true),
        @Result(property = "username", column = "username"),
        @Result(property = "birthday", column = "birthday"),
        @Result(property = "sex",      column = "sex"),
        @Result(property = "address",  column = "address")
    })
    List<User> findAll();

    // 根据 id 查询
    @Select("select * from user where id = #{id}")
    @ResultMap("userMap")
    User findById(int id);

    // 新增
    @Insert("insert into user(username, birthday, sex, address) " +
            "values(#{username}, #{birthday}, #{sex}, #{address})")
    void insert(User user);

    // 修改
    @Update("update user set username=#{username}, birthday=#{birthday}, " +
            "sex=#{sex}, address=#{address} where id=#{id}")
    void update(User user);

    // 删除
    @Delete("delete from user where id = #{id}")
    void delete(int id);
}

五、注解开发中注册 Mapper

注解开发不再有 mapper.xml 文件,sqlMapConfig.xml 中注册方式也要改变:

XML 开发(指向文件):

<mappers>
    <mapper resource="mapper/UserMapper.xml"/>
</mappers>

注解开发(指向接口类):

<mappers>
    <mapper class="com.qcby.dao.UserDao"/>
    <mapper class="com.qcby.dao.StudentDao"/>
    <mapper class="com.qcby.dao.TeacherDao"/>
</mappers>

原理:SQL 已经通过注解写在接口里,MyBatis 直接扫描接口类即可找到所有 SQL,不再需要 XML 文件。


六、注解开发中开启二级缓存

XML 开发用 <cache/> 标签,注解开发用 @CacheNamespace

@CacheNamespace   // 对应 XML 里的 <cache/>
public interface UserDao {
    // ...
}

带参数的配置:

@CacheNamespace(
    eviction      = FifoCache.class,  // 淘汰策略:先进先出
    flushInterval = 60000,            // 每 60 秒刷新一次缓存
    size          = 512,              // 最多缓存 512 个对象
    readWrite     = true              // 开启读写缓存(需要序列化)
)
public interface UserDao {
    // ...
}

注意:开启二级缓存后,实体类必须实现 Serializable 接口,否则运行时会报错。


七、注解开发 vs XML 开发,如何选择

推荐注解开发的场景:

  • 简单的单表 CRUD
  • SQL 逻辑固定,不需要动态拼接
  • 追求代码简洁,减少 XML 文件

推荐 XML 开发的场景:

  • 复杂的动态 SQL(<if><foreach><choose> 等)
  • SQL 较长,注解里写会影响可读性
  • 需要精细的 SQL 调优和维护

实际项目中两种方式可以混用,简单查询用注解,复杂查询用 XML。


总结

@Select/@Insert/@Update/@Delete直接在接口方法上写 SQL,替代 XML 标签
@Results + @Result替代 <resultMap>,处理字段名不一致
@ResultMap复用已声明的 @Results,避免重复配置
mapper 注册方式注解开发用 class=,XML 开发用 resource=
@CacheNamespace替代 <cache/>,开启接口级别的二级缓存
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐