一、ResultType 和 ParameterType 讲解

1. resultType

  • 作用: 定义 SQL 查询结果的返回类型,即将数据库查询的结果集映射到 Java 对象或基本数据类型的类型。每一条数据库记录的数据应该被映射成什么 Java 类型
  • 使用场景:

    • 用于 SELECT 语句,返回查询结果。
    • 最常见场景:resultType 用于 SELECT 语句的查询结果映射
    • resultType 不仅限于 SELECT 查询语句,而是适用于任何有返回值的 SQL 语句,
    • 通常是 Java 实体类(如 com.example.User)、基本数据类型(如 java.lang.Integer)、Map(如 java.util.Map)等。
  • 常见写法:

    <select id="selectUserById" resultType="com.example.User">
        SELECT * FROM user WHERE id = #{id}
    </select>
    • 这里 resultType="com.example.User" 表示查询结果会映射为 User 类的对象。
  • 注意事项:

    • 如果查询结果是多条记录,MyBatis 会将 resultType 类型的对象放入 List 返回(如 List<User>)。
    • 如果查询结果的列名和 Java 类的属性名不一致,需要使用 resultMap 来定义映射关系。
    • resultTypeSELECT 语句中必须的(除非使用 resultMap)。

2. parameterType

  • 作用: 定义 SQL 语句的输入参数类型,即传递给 SQL 的参数的 Java 类型。
  • 使用场景:

    • 用于任何需要传入参数的 SQL 语句(如 SELECTINSERTUPDATEDELETE)。
    • 可以是基本数据类型(如 java.lang.Integer)、Java 实体类(如 com.example.User)、Map、List 等。
  • 常见写法:

    <select id="selectUserById" parameterType="java.lang.Integer" resultType="com.example.User">
        SELECT * FROM user WHERE id = #{id}
    </select>
    • 这里 parameterType="java.lang.Integer" 表示传入的参数是一个整数类型。
  • 注意事项:

    • 如果 SQL 语句没有参数,parameterType 可以省略。
    • 如果传入多个参数,通常需要使用 @Param 注解或 Map 类型来明确参数名称。

3. 什么时候用 resultTypeparameterType

  • resultType:

    • 必须使用:在 SELECT 语句中,用于指定返回结果的类型。
    • 何时省略:如果使用 resultMap 来定义结果映射,resultType 可以省略(resultMapresultType 互斥)。
    • 例子:

      <select id="selectUserById" resultMap="userResultMap">
          SELECT * FROM user WHERE id = #{id}
      </select>

      这里用 resultMap 替代了 resultType

  • parameterType:

    • 可选使用:在任何需要参数的 SQL 语句中,用于明确参数类型。
    • 何时省略

      • MyBatis 可以通过反射自动推断参数类型,尤其是当参数是基本类型、实体类或单个参数时。
      • 例如:

        <select id="selectUserById" resultType="com.example.User">
            SELECT * FROM user WHERE id = #{id}
        </select>

        这里省略了 parameterType,MyBatis 会根据 Mapper 接口的方法签名推断参数类型(如 Integer)。

    • 需要显式指定

      • 当参数类型复杂(如 Map、List 或多个参数)时,建议显式指定 parameterType 以提高可读性和避免歧义。
      • 例如:

        <insert id="insertUser" parameterType="com.example.User">
            INSERT INTO user (name, age) VALUES (#{name}, #{age})
        </insert>

4. 什么有时候省略 parameterType 不报错

MyBatis 允许省略 parameterType 不报错的原因在于其参数类型推断机制

  • MyBatis 会根据 Mapper 接口的方法签名,通过 Java 反射机制自动推断参数的类型。
  • 例如:

    public interface UserMapper {
        User selectUserById(Integer id);
    }

    对应的 XML:

    <select id="selectUserById" resultType="com.example.User">
        SELECT * FROM user WHERE id = #{id}
    </select>
    • 这里 MyBatis 能从方法签名 Integer id 推断出参数类型是 java.lang.Integer,因此无需显式指定 parameterType
  • 推断机制的适用场景:

    • 单个参数(基本类型、实体类等)。
    • 参数名称在 SQL 中通过 #{paramName} 直接引用。
  • 推断机制的局限性:

    • 如果方法有多个参数,未使用 @Param 注解,MyBatis 会将参数命名为 param1param2 等,可能导致 SQL 引用参数时出错。
    • 如果参数类型复杂(如 Map 或 List),推断可能不准确,建议显式指定 parameterType
  • 推断机制的适用场景:

    • 单个参数(基本类型、实体类等):

      • 基本类型:指 Java 的基本数据类型及其包装类,如 intIntegerStringdoubleDoublebooleanBoolean 等。这些类型是单一值,MyBatis 可以直接通过方法签名推断。

        • 示例:查询用户通过 ID(Integer 作为参数)。

          public interface UserMapper {
              User selectUserById(Integer id);
          }
          <select id="selectUserById" resultType="com.example.User">
              SELECT * FROM user WHERE id = #{id}
          </select>
          • #{id} 引用 Integer 参数,MyBatis 自动推断类型为 java.lang.Integer
        • 另一个示例:使用 String 查询用户名。

          public interface UserMapper {
              List<User> selectUsersByName(String name);
          }
          <select id="selectUsersByName" resultType="com.example.User">
              SELECT * FROM user WHERE name = #{name}
          </select>
          • 参数为 String,MyBatis 推断为 java.lang.String,无需 parameterType
      • 实体类:指自定义的 Java 类(POJO),如 UserOrder 等,通常用于映射数据库表中的一行数据。MyBatis 通过反射获取实体类的属性名和类型。

        • 示例:插入用户数据(User 实体类作为参数)。

          public class User {
              private Integer id;
              private String name;
              private Integer age;
              // getters and setters
          }
          
          public interface UserMapper {
              int insertUser(User user);
          }
          <insert id="insertUser" resultType="java.lang.Integer">
              INSERT INTO user (name, age) VALUES (#{name}, #{age})
          </insert>
          • #{name}#{age} 引用 User 对象的属性,MyBatis 自动推断类型为 com.example.User
      • 其他单个复杂类型:如 MapList,当作为单个参数时,MyBatis 也能推断类型。

        • 示例:使用 Map 更新用户数据。

          public interface UserMapper {
              int updateUserByMap(Map<String, Object> params);
          }
          <update id="updateUserByMap" resultType="java.lang.Integer">
              UPDATE user SET name = #{name}, age = #{age} WHERE id = #{id}
          </update>
          • #{name}#{age}#{id} 引用 Map 的键,MyBatis 推断类型为 java.util.Map
    • 参数名称在 SQL 中通过 #{paramName} 直接引用。
  • 推断机制的局限性:

    • 如果方法有多个参数,可以不使用@ParameterType,且这时若未使用 @Param 注解,MyBatis 会将参数自动命名为 param1param2 等,有可能给自己挖坑,导致 SQL 引用参数时出错。

      • 示例:多个参数未使用 @Param

        public interface UserMapper {
            List<User> selectUsersByNameAndAge(String name, Integer age);
        }
        <select id="selectUsersByNameAndAge" resultType="com.example.User">
            SELECT * FROM user WHERE name = #{param1} AND age = #{param2}
        </select>
        • 参数被命名为 param1param2,引用不够直观,维护性差。
        • 对于多个参数,MyBatis 将它们视为一个隐式的参数集合(内部以类似 Map 的形式处理),并为每个参数分配默认名称(param1param2 等)。
        • 虽然参数名称是 param1param2,但 MyBatis 仍然知道每个参数的实际类型(通过反射),因此无需显式指定 parameterType
      • 使用 @Param 改进:

        public interface UserMapper {
            List<User> selectUsersByNameAndAge(@Param("name") String name, @Param("age") Integer age);
        }
        <select id="selectUsersByNameAndAge" resultType="com.example.User">
            SELECT * FROM user WHERE name = #{name} AND age = #{age}
        </select>
        • @Param 指定参数名称,MyBatis 自动推断类型,parameterType 可省略。
    • 如果参数类型复杂(如 MapList),推断可能不准确,建议显式指定 parameterType 以提高可读性和避免歧义.

      • 示例:显式指定 Map 类型。

        public interface UserMapper {
            int updateUserByMap(Map<String, Object> params);
        }
        <update id="updateUserByMap" parameterType="map" resultType="java.lang.Integer">
            UPDATE user SET name = #{name}, age = #{age} WHERE id = #{id}
        </update>
        • 显式指定 parameterType="map",增强代码可读性。

5. 总结

属性作用是否必须省略场景
resultType定义查询结果的返回类型SELECT 语句中通常必须使用 resultMap 时可省略
parameterType定义 SQL 语句的输入参数类型可选单个参数、MyBatis 能自动推断类型时可省略;复杂参数或多参数建议显式指定

建议

  • 对于简单查询,省略 parameterType 是可以接受的,MyBatis 的类型推断机制能正确处理。
  • 对于复杂场景(如多参数、动态 SQL、Map 或 List 参数),显式指定 parameterType 可以提高代码可读性和稳定性。
  • 始终为 SELECT 语句指定 resultTyperesultMap,以确保结果映射正确。

6. ✅ resultType vs parameterType 写法对照

类型分类parameterType 写法resultType 写法是否写全类名?
基本类型(如 int)intint❌ 可简写(内置别名)
包装类(如 Integer)java.lang.Integerintjava.lang.Integerint✅ 推荐写全名,也可简写
字符串stringjava.lang.Stringstringjava.lang.String❌ 推荐写简写
JavaBean(如 User)com.example.Usercom.example.User✅ 必须写全类名
Map<String, Object>mapjava.util.Mapmapjava.util.Map✅ 推荐写简写
List不写 List,写 T 的类名即可写 T 的类名(如 User✅ 只写元素类全名

🧠 理解要点总结:

  • parameterType:是你传入方法的参数类型,通常要写全类名
  • resultType:是每一条记录映射成的对象类型,MyBatis 自动封装成集合时你只写元素类名即可
  • ❌ 都不直接写 List<xxx> 这种泛型形式,MyBatis 不能识别
  • mapstringint 等可以用内置别名,不用全类名

resultMap 详解及多参数使用 @Param

一、resultMap 是什么?

  • 作用: resultMap 用于显式定义数据库查询结果的列与 Java 对象属性的映射关系,解决列名与属性名不一致、复杂对象映射(如嵌套对象、关联查询)等问题。
  • resultType 的区别:

    • resultType 直接指定返回的 Java 类型,依赖列名与属性名一致或通过别名解决不一致问题。
    • resultMap 提供更精细的映射控制,支持复杂场景,如一对一、一对多关联查询、嵌套对象等。
  • 使用场景:

    • 数据库列名与 Java 对象的属性名不一致。
    • 需要映射复杂对象(如包含嵌套对象或集合)。
    • 处理关联查询(一对一、一对多)。
    • 需要复用映射规则。

二、如何使用 resultMap

1. 基本结构

<resultMap id="userResultMap" type="com.example.User">
    <id property="id" column="user_id" />
    <result property="name" column="user_name" />
    <result property="age" column="user_age" />
</resultMap>

<select id="selectUserById" resultMap="userResultMap">
    SELECT user_id, user_name, user_age FROM user WHERE user_id = #{id}
</select>
  • 说明:

    • id: 唯一标识 resultMap,供 SELECT 语句引用。
    • type: 指定映射的目标 Java 类(如 com.example.User)。
    • <id>: 定义主键的映射,property 是 Java 对象的属性名,column 是数据库的列名。
    • <result>: 定义普通字段的映射。
    • <select> 中通过 resultMap="userResultMap" 引用。

2. 复杂映射(嵌套对象或集合)

resultMap 支持嵌套对象或集合的映射,使用 <association><collection> 标签。

例子:一对一映射(用户和地址)
假设 User 类包含一个 Address 对象:

public class User {
    private Integer id;
    private String name;
    private Address address; // 嵌套对象
    // getters and setters
}

public class Address {
    private Integer addressId;
    private String city;
    // getters and setters
}

对应的 resultMap

<resultMap id="userWithAddressMap" type="com.example.User">
    <id property="id" column="user_id" />
    <result property="name" column="user_name" />
    <association property="address" javaType="com.example.Address">
        <id property="addressId" column="address_id" />
        <result property="city" column="city" />
    </association>
</resultMap>

<select id="selectUserWithAddress" resultMap="userWithAddressMap">
    SELECT u.user_id, u.user_name, a.address_id, a.city 
    FROM user u 
    LEFT JOIN address a ON u.address_id = a.address_id 
    WHERE u.user_id = #{id}
</select>
  • 说明:

    • <association>: 用于一对一映射,propertyUser 类的 address 属性,javaType 指定嵌套对象的类型。
    • 查询结果会将 address_idcity 映射到 Address 对象,并赋值给 Useraddress 属性。

例子:一对多映射(用户和订单)
假设 User 类包含一个订单列表:

public class User {
    private Integer id;
    private String name;
    private List<Order> orders; // 嵌套集合
    // getters and setters
}

public class Order {
    private Integer orderId;
    private String orderName;
    // getters and setters
}

对应的 resultMap

<resultMap id="userWithOrdersMap" type="com.example.User">
    <id property="id" column="user_id" />
    <result property="name" column="user_name" />
    <collection property="orders" ofType="com.example.Order">
        <id property="orderId" column="order_id" />
        <result property="orderName" column="order_name" />
    </collection>
</resultMap>

<select id="selectUserWithOrders" resultMap="userWithOrdersMap">
    SELECT u.user_id, u.user_name, o.order_id, o.order_name 
    FROM user u 
    LEFT JOIN orders o ON u.user_id = o.user_id 
    WHERE u.user_id = #{id}
</select>
  • 说明:

    • <collection>: 用于一对多映射,propertyUser 类的 orders 属性,ofType 指定集合中元素的类型。
    • 查询结果会将 order_idorder_name 映射到 Order 对象,并放入 Userorders 列表。

三、resultMap 的使用规则

  1. 定义位置:

    • resultMap 定义在 MyBatis 的 XML 配置文件中,通常与 <mapper> 标签同级。
    • 可以在多个 <select> 语句中复用同一个 resultMap
  2. resultType 的互斥性:

    • 一个 <select> 语句只能使用 resultMapresultType,不能同时使用。
    • 如果列名与属性名完全一致,resultType 更简单;否则,resultMap 更适合。
  3. 主键与普通字段:

    • 使用 <id> 定义主键映射,有助于 MyBatis 优化缓存和对象跟踪。
    • 使用 <result> 定义普通字段映射。
  4. 支持继承:

    • resultMap 可以通过 extends 继承另一个 resultMap,复用已有映射规则。
    • 例如:

      <resultMap id="extendedUserMap" type="com.example.User" extends="userResultMap">
          <result property="extraField" column="extra_field" />
      </resultMap>
  5. 动态映射:

    • resultMap 可以结合动态 SQL(如 <if><choose>)实现灵活的映射逻辑。
  6. 懒加载:

    • 对于 <association><collection>,可以启用懒加载(通过 fetchType="lazy" 或全局配置),延迟加载关联数据以提高性能。

四、多个参数如何使用 @Param

1. 使用 @Param 的步骤

  1. 在 Mapper 接口中添加 @Param 注解

    public interface UserMapper {
        List<User> selectUsersByNameAndAge(@Param("name") String name, @Param("age") Integer age);
    }
    • @Param("name") 为第一个参数指定名称 name
    • @Param("age") 为第二个参数指定名称 age.
  2. 在 XML 中使用参数名称

    <select id="selectUsersByNameAndAge" resultType="com.example.User">
        SELECT * FROM user 
        WHERE name = #{name} AND age = #{age}
    </select>
    • 使用 #{name}#{age} 直接引用参数。
  3. 结合 resultMap
    如果查询结果需要复杂映射,可以结合 resultMap

    <resultMap id="userResultMap" type="com.example.User">
        <id property="id" column="user_id" />
        <result property="name" column="user_name" />
        <result property="age" column="user_age" />
    </resultMap>
    
    <select id="selectUsersByNameAndAge" resultMap="userResultMap">
        SELECT user_id, user_name, user_age 
        FROM user 
        WHERE user_name = #{name} AND user_age = #{age}
    </select>

2. 省略 parameterType

  • 当使用 @Param 注解时,MyBatis 会自动推断参数类型,因此通常无需显式指定 parameterType
  • 如果需要显式指定,可以在 XML 中添加:

    <select id="selectUsersByNameAndAge" parameterType="map" resultMap="userResultMap">
        SELECT user_id, user_name, user_age 
        FROM user 
        WHERE user_name = #{name} AND user_age = #{age}
    </select>
    • 这里 parameterType="map" 表示参数被视为一个 Map,键为 @Param 指定的名称。

3. 不使用 @Param 的情况

如果不使用 @Param,MyBatis 会将多个参数视为 param1param2 等:

public interface UserMapper {
    List<User> selectUsersByNameAndAge(String name, Integer age);
}

对应的 XML:

<select id="selectUsersByNameAndAge" resultType="com.example.User">
    SELECT * FROM user 
    WHERE name = #{param1} AND age = #{param2}
</select>
  • 这种方式可行,但参数名称不直观,维护性较差,推荐使用 @Param

五、总结

  • resultMap:

    • 用于定义复杂的列到属性的映射,支持嵌套对象(<association>)、集合(<collection>)和自定义映射规则。
    • 适合列名与属性名不一致、关联查询等场景。
    • 使用规则:定义在 XML 中,通过 id 引用,支持继承和懒加载。
  • 多个参数与 @Param:

    • 使用 @Param 注解为多个参数指定名称,便于在 XML 中通过 #{name} 引用。
    • 省略 parameterType 时,MyBatis 自动推断参数类型。
    • 不使用 @Param 时,参数以 param1param2 命名,可读性较差。

建议

  • 对于简单查询,使用 resultType 和自动参数推断即可。
  • 对于复杂映射或多参数场景,结合 resultMap@Param 提高代码可读性和灵活性。
  • 在 XML 中尽量保持映射规则清晰,避免过度复杂的动态 SQL。

文章作者: 无念log
文章链接: https://silys.nianlink.top/index.php/archives/108/
版权声明: 本网站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 伤极无念log-科技、爱好、工具!
分类: 默认分类 标签: JavaMybatis

评论

-- 评论已关闭 --

目录