MyBatis 通过 XML 方式进行配置写 SQL
一、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
来定义映射关系。 resultType
是SELECT
语句中必须的(除非使用resultMap
)。
- 如果查询结果是多条记录,MyBatis 会将
2. parameterType
- 作用: 定义 SQL 语句的输入参数类型,即传递给 SQL 的参数的 Java 类型。
使用场景:
- 用于任何需要传入参数的 SQL 语句(如
SELECT
、INSERT
、UPDATE
、DELETE
)。 - 可以是基本数据类型(如
java.lang.Integer
)、Java 实体类(如com.example.User
)、Map、List 等。
- 用于任何需要传入参数的 SQL 语句(如
常见写法:
<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 类型来明确参数名称。
- 如果 SQL 语句没有参数,
3. 什么时候用 resultType
和 parameterType
resultType
:- 必须使用:在
SELECT
语句中,用于指定返回结果的类型。 - 何时省略:如果使用
resultMap
来定义结果映射,resultType
可以省略(resultMap
和resultType
互斥)。 例子:
<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>
- 当参数类型复杂(如 Map、List 或多个参数)时,建议显式指定
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
。
- 这里 MyBatis 能从方法签名
推断机制的适用场景:
- 单个参数(基本类型、实体类等)。
- 参数名称在 SQL 中通过
#{paramName}
直接引用。
推断机制的局限性:
- 如果方法有多个参数,未使用
@Param
注解,MyBatis 会将参数命名为param1
、param2
等,可能导致 SQL 引用参数时出错。 - 如果参数类型复杂(如 Map 或 List),推断可能不准确,建议显式指定
parameterType
。
- 如果方法有多个参数,未使用
推断机制的适用场景:
单个参数(基本类型、实体类等):
基本类型:指 Java 的基本数据类型及其包装类,如
int
、Integer
、String
、double
、Double
、boolean
、Boolean
等。这些类型是单一值,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),如
User
、Order
等,通常用于映射数据库表中的一行数据。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
。
其他单个复杂类型:如
Map
或List
,当作为单个参数时,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 会将参数自动命名为param1
、param2
等,有可能给自己挖坑,导致 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>
- 参数被命名为
param1
和param2
,引用不够直观,维护性差。 - 对于多个参数,MyBatis 将它们视为一个隐式的参数集合(内部以类似 Map 的形式处理),并为每个参数分配默认名称(
param1
、param2
等)。 - 虽然参数名称是
param1
、param2
,但 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
可省略。
如果参数类型复杂(如
Map
或List
),推断可能不准确,建议显式指定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
语句指定resultType
或resultMap
,以确保结果映射正确。
6. ✅ resultType
vs parameterType
写法对照
类型分类 | parameterType 写法 | resultType 写法 | 是否写全类名? |
---|---|---|---|
基本类型(如 int) | int | int | ❌ 可简写(内置别名) |
包装类(如 Integer) | java.lang.Integer 或 int | java.lang.Integer 或 int | ✅ 推荐写全名,也可简写 |
字符串 | string 或 java.lang.String | string 或 java.lang.String | ❌ 推荐写简写 |
JavaBean(如 User) | com.example.User | com.example.User | ✅ 必须写全类名 |
Map<String, Object> | map 或 java.util.Map | map 或 java.util.Map | ✅ 推荐写简写 |
List | 不写 List ,写 T 的类名即可 | 写 T 的类名(如 User ) | ✅ 只写元素类全名 |
🧠 理解要点总结:
- ✅
parameterType
:是你传入方法的参数类型,通常要写全类名 - ✅
resultType
:是每一条记录映射成的对象类型,MyBatis 自动封装成集合时你只写元素类名即可 - ❌ 都不直接写
List<xxx>
这种泛型形式,MyBatis 不能识别 - ❌
map
和string
、int
等可以用内置别名,不用全类名
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>
: 用于一对一映射,property
是User
类的address
属性,javaType
指定嵌套对象的类型。- 查询结果会将
address_id
和city
映射到Address
对象,并赋值给User
的address
属性。
例子:一对多映射(用户和订单)
假设 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>
: 用于一对多映射,property
是User
类的orders
属性,ofType
指定集合中元素的类型。- 查询结果会将
order_id
和order_name
映射到Order
对象,并放入User
的orders
列表。
三、resultMap
的使用规则
定义位置:
resultMap
定义在 MyBatis 的 XML 配置文件中,通常与<mapper>
标签同级。- 可以在多个
<select>
语句中复用同一个resultMap
。
与
resultType
的互斥性:- 一个
<select>
语句只能使用resultMap
或resultType
,不能同时使用。 - 如果列名与属性名完全一致,
resultType
更简单;否则,resultMap
更适合。
- 一个
主键与普通字段:
- 使用
<id>
定义主键映射,有助于 MyBatis 优化缓存和对象跟踪。 - 使用
<result>
定义普通字段映射。
- 使用
支持继承:
resultMap
可以通过extends
继承另一个resultMap
,复用已有映射规则。例如:
<resultMap id="extendedUserMap" type="com.example.User" extends="userResultMap"> <result property="extraField" column="extra_field" /> </resultMap>
动态映射:
resultMap
可以结合动态 SQL(如<if>
、<choose>
)实现灵活的映射逻辑。
懒加载:
- 对于
<association>
和<collection>
,可以启用懒加载(通过fetchType="lazy"
或全局配置),延迟加载关联数据以提高性能。
- 对于
四、多个参数如何使用 @Param
1. 使用 @Param
的步骤
在 Mapper 接口中添加
@Param
注解:public interface UserMapper { List<User> selectUsersByNameAndAge(@Param("name") String name, @Param("age") Integer age); }
@Param("name")
为第一个参数指定名称name
。@Param("age")
为第二个参数指定名称age
.
在 XML 中使用参数名称:
<select id="selectUsersByNameAndAge" resultType="com.example.User"> SELECT * FROM user WHERE name = #{name} AND age = #{age} </select>
- 使用
#{name}
和#{age}
直接引用参数。
- 使用
结合
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 会将多个参数视为 param1
、param2
等:
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
时,参数以param1
、param2
命名,可读性较差。
- 使用
建议:
- 对于简单查询,使用
resultType
和自动参数推断即可。 - 对于复杂映射或多参数场景,结合
resultMap
和@Param
提高代码可读性和灵活性。 - 在 XML 中尽量保持映射规则清晰,避免过度复杂的动态 SQL。
文章链接: https://silys.nianlink.top/index.php/archives/108/
版权声明: 本网站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 伤极无念log-科技、爱好、工具!
评论