MyBatis注解与XML使用对比
1. MyBatis 注解方式
基本 CRUD 注解
java
@Mapper
public interface UserMapper {// 查询@Select("SELECT * FROM users WHERE id = #{id}")User findById(Long id);// 插入@Insert("INSERT INTO users(name, email, age) VALUES(#{name}, #{email}, #{age})")@Options(useGeneratedKeys = true, keyProperty = "id")int insert(User user);// 更新@Update("UPDATE users SET name=#{name}, email=#{email}, age=#{age} WHERE id=#{id}")int update(User user);// 删除@Delete("DELETE FROM users WHERE id = #{id}")int deleteById(Long id);
}结果映射注解
java
@Mapper
public interface UserMapper {@Results({@Result(property = "id", column = "id"),@Result(property = "userName", column = "username"),@Result(property = "email", column = "email"),@Result(property = "createTime", column = "create_time")})@Select("SELECT * FROM users WHERE id = #{id}")User findUserWithMapping(Long id);// 一对一关联查询@Results({@Result(property = "id", column = "id"),@Result(property = "userName", column = "username"),@Result(property = "profile", column = "user_id", one = @One(select = "findProfileByUserId"))})@Select("SELECT * FROM users WHERE id = #{id}")User findUserWithProfile(Long id);@Select("SELECT * FROM user_profile WHERE user_id = #{userId}")UserProfile findProfileByUserId(Long userId);
}动态 SQL 注解
java
@Mapper
public interface UserMapper {// 使用脚本实现动态 SQL@Select("<script>" +"SELECT * FROM users " +"WHERE 1=1 " +"<if test='name != null'> AND name LIKE CONCAT('%', #{name}, '%')</if>" +"<if test='email != null'> AND email = #{email}</if>" +"<if test='minAge != null'> AND age >= #{minAge}</if>" +"<if test='maxAge != null'> AND age <= #{maxAge}</if>" +"</script>")List<User> findUsersByCondition(@Param("name") String name,@Param("email") String email,@Param("minAge") Integer minAge,@Param("maxAge") Integer maxAge);// 批量插入@Insert("<script>" +"INSERT INTO users(name, email, age) VALUES " +"<foreach collection='users' item='user' separator=','>" +"(#{user.name}, #{user.email}, #{user.age})" +"</foreach>" +"</script>")int batchInsert(@Param("users") List<User> users);
}2. MyBatis XML 方式
Mapper 接口
java
@Mapper
public interface UserMapper {User findById(Long id);List<User> findByCondition(UserQuery query);int insert(User user);int update(User user);int deleteById(Long id);int batchInsert(List<User> users);
}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"><!-- 结果映射 --><resultMap id="UserResultMap" type="com.example.entity.User"><id property="id" column="id" /><result property="userName" column="username" /><result property="email" column="email" /><result property="age" column="age" /><result property="createTime" column="create_time" /><result property="updateTime" column="update_time" /></resultMap><!-- 基础查询 --><select id="findById" parameterType="Long" resultMap="UserResultMap">SELECT * FROM users WHERE id = #{id}</select><!-- 动态 SQL 查询 --><select id="findByCondition" parameterType="UserQuery" resultMap="UserResultMap">SELECT * FROM users<where><if test="userName != null and userName != ''">AND username LIKE CONCAT('%', #{userName}, '%')</if><if test="email != null and email != ''">AND email = #{email}</if><if test="minAge != null">AND age >= #{minAge}</if><if test="maxAge != null">AND age <= #{maxAge}</if><if test="createTimeStart != null">AND create_time >= #{createTimeStart}</if><if test="createTimeEnd != null">AND create_time <= #{createTimeEnd}</if></where>ORDER BY create_time DESC</select><!-- 插入 --><insert id="insert" parameterType="User" useGeneratedKeys="true" keyProperty="id">INSERT INTO users (username, email, age, create_time)VALUES (#{userName}, #{email}, #{age}, NOW())</insert><!-- 批量插入 --><insert id="batchInsert" parameterType="java.util.List">INSERT INTO users (username, email, age, create_time)VALUES<foreach collection="list" item="user" separator=",">(#{user.userName}, #{user.email}, #{user.age}, NOW())</foreach></insert><!-- 更新 --><update id="update" parameterType="User">UPDATE users<set><if test="userName != null">username = #{userName},</if><if test="email != null">email = #{email},</if><if test="age != null">age = #{age},</if>update_time = NOW()</set>WHERE id = #{id}</update><!-- 删除 --><delete id="deleteById" parameterType="Long">DELETE FROM users WHERE id = #{id}</delete></mapper>复杂关联查询 XML
xml
<!-- 一对一关联 -->
<resultMap id="UserWithProfileResultMap" type="User" extends="UserResultMap"><association property="profile" javaType="UserProfile"><id property="id" column="profile_id" /><result property="realName" column="real_name" /><result property="phone" column="phone" /><result property="address" column="address" /></association>
</resultMap><select id="findUserWithProfile" parameterType="Long" resultMap="UserWithProfileResultMap">SELECT u.*, p.id as profile_id, p.real_name, p.phone, p.addressFROM users uLEFT JOIN user_profile p ON u.id = p.user_idWHERE u.id = #{id}
</select><!-- 一对多关联 -->
<resultMap id="UserWithOrdersResultMap" type="User" extends="UserResultMap"><collection property="orders" ofType="Order"><id property="id" column="order_id" /><result property="orderNo" column="order_no" /><result property="amount" column="amount" /><result property="createTime" column="order_create_time" /></collection>
</resultMap><select id="findUserWithOrders" parameterType="Long" resultMap="UserWithOrdersResultMap">SELECT u.*,o.id as order_id,o.order_no,o.amount,o.create_time as order_create_timeFROM users uLEFT JOIN orders o ON u.id = o.user_idWHERE u.id = #{id}
</select>3. 注解 vs XML 对比
注解方式的优缺点
优点:
代码简洁,SQL 与 Java 代码在一起
无需额外的 XML 文件
类型安全,编译时检查
重构友好
缺点:
复杂 SQL 可读性差
动态 SQL 编写麻烦
不支持所有 MyBatis 特性
字符串形式,无语法高亮和提示
XML 方式的优缺点
优点:
复杂 SQL 可读性好
强大的动态 SQL 支持
完整的 MyBatis 特性支持
良好的 IDE 支持(语法高亮、提示)
SQL 与 Java 代码分离
缺点:
需要维护额外的 XML 文件
配置相对繁琐
类型不安全,运行时错误
4. 实际应用建议
推荐使用注解的场景
java
// 简单的 CRUD 操作
@Mapper
public interface SimpleUserMapper {@Select("SELECT COUNT(*) FROM users WHERE status = #{status}")long countByStatus(@Param("status") Integer status);@Select("SELECT * FROM users WHERE email = #{email}")User findByEmail(String email);@Update("UPDATE users SET last_login_time = NOW() WHERE id = #{id}")int updateLastLoginTime(Long id);
}推荐使用 XML 的场景
xml
<!-- 复杂的统计查询 -->
<select id="findUserStatistics" resultType="UserStatistics">SELECT COUNT(*) as totalUsers,COUNT(CASE WHEN age < 18 THEN 1 END) as minorCount,COUNT(CASE WHEN age BETWEEN 18 AND 60 THEN 1 END) as adultCount,COUNT(CASE WHEN age > 60 THEN 1 END) as seniorCount,AVG(age) as averageAge,MAX(create_time) as latestCreateTimeFROM usersWHERE status = 1
</select><!-- 复杂的分页查询 -->
<select id="findUsersWithPagination" parameterType="UserQuery" resultMap="UserResultMap">SELECT * FROM users<where><include refid="userQueryConditions"/></where>ORDER BY <choose><when test="sortField == 'name'">username</when><when test="sortField == 'email'">email</when><when test="sortField == 'createTime'">create_time</when><otherwise>id</otherwise></choose><if test="sortOrder != null and sortOrder == 'desc'">DESC</if>LIMIT #{offset}, #{pageSize}
</select><!-- 可重用的 SQL 片段 -->
<sql id="userQueryConditions"><if test="userName != null and userName != ''">AND username LIKE CONCAT('%', #{userName}, '%')</if><if test="status != null">AND status = #{status}</if>
</sql>5. 混合使用方式
在实际项目中,可以混合使用注解和 XML:
java
@Mapper
public interface UserMapper {// 简单查询使用注解@Select("SELECT * FROM users WHERE id = #{id}")User findById(Long id);@Select("SELECT * FROM users WHERE email = #{email}")User findByEmail(String email);// 复杂查询使用 XMLList<User> findByComplexCondition(UserQuery query);List<UserStatistics> findUserStatistics();int batchUpdate(List<User> users);
}6. 配置说明
application.yml 配置
yaml
mybatis:# XML 映射文件位置mapper-locations: classpath:mapper/*.xml# 实体类包路径type-aliases-package: com.example.entity# 开启驼峰命名转换configuration:map-underscore-to-camel-case: truelog-impl: org.apache.ibatis.logging.stdout.StdOutImpl
依赖配置
xml
<dependencies><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId> https://rd.xjyl.gov.cn/upload/1981730209542930432.html https://rd.xjyl.gov.cn/upload/1981730209110917120.html https://rd.xjyl.gov.cn/upload/1981730209496793088.html https://rd.xjyl.gov.cn/upload/1981730209555513344.html https://rd.xjyl.gov.cn/upload/1981730209865891840.html https://rd.xjyl.gov.cn/upload/1981730209983332352.html https://rd.xjyl.gov.cn/upload/1981730210176270336.html https://rd.xjyl.gov.cn/upload/1981730208825704448.html https://rd.xjyl.gov.cn/upload/1981730209136082944.html https://rd.xjyl.gov.cn/upload/1981730210339848192.html https://rd.xjyl.gov.cn/upload/1981730210306293760.html https://rd.xjyl.gov.cn/upload/1981730210868330496.html https://rd.xjyl.gov.cn/upload/1981730210302099456.html https://rd.xjyl.gov.cn/upload/1981730210809610240.html https://rd.xjyl.gov.cn/upload/1981730210968993792.html https://rd.xjyl.gov.cn/upload/1981730211027714048.html https://rd.xjyl.gov.cn/upload/1981730211388424192.html https://rd.xjyl.gov.cn/upload/1981730211199680512.html https://rd.xjyl.gov.cn/upload/1981730211677831168.html https://rd.xjyl.gov.cn/upload/1981730211791077376.html https://rd.xjyl.gov.cn/upload/1981730211610722304.html https://rd.xjyl.gov.cn/upload/1981730211493281792.html https://rd.xjyl.gov.cn/upload/1981730211518447616.html https://rd.xjyl.gov.cn/upload/1981730212155981824.html https://rd.xjyl.gov.cn/upload/1981730211673636864.html https://rd.xjyl.gov.cn/upload/1981730210721529856.html https://rd.xjyl.gov.cn/upload/1981730212168564736.html https://rd.xjyl.gov.cn/upload/1981730212214702080.html https://rd.xjyl.gov.cn/upload/1981730212713824256.html<version>2.3.1</version></dependency> </dependencies>
总结
简单场景:推荐使用注解,代码简洁明了
复杂场景:推荐使用 XML,可读性和维护性更好
混合使用:根据实际情况选择最合适的方式
团队规范:统一团队的开发规范,保持一致性
根据项目复杂度和团队习惯,合理选择注解和 XML 的使用比例,可以达到最佳的开发效率和代码质量。
