MyBatis 查询结果接收类型的总结与实践
基本情况
1. 实体类型(Java Bean)
实体类型是最常用的接收方式之一,适用于结果集与实体类字段一一对应的情况。这种方式不仅便于后续处理,还能够充分利用对象关系映射(ORM)的优势。
示例代码:
public interface UserMapper {
User getUserById(Integer id);
}
<select id="getUserById" resultType="com.example.model.User">
SELECT * FROM users WHERE id = #{id}
</select>
2. Map 类型
当结果集中的字段与实体类不完全匹配,或者需要处理复杂的结构(如嵌套查询结果)时,可以选择将结果集映射为 Map
。这种方式虽然较为灵活,但不如实体类直观。
示例代码:
public interface UserMapper {
Map<String, Object> getUserById(Integer id);
}
<select id="getUserById" resultType="java.util.Map">
SELECT id, name, email FROM users WHERE id = #{id}
</select>
3. 自定义结果类型
有时需要返回自定义的结果类型,这时可以使用 resultMap
来定义复杂的映射逻辑。这种方式适用于需要组合多个表数据的情况。
示例代码:
<resultMap id="UserResultMap" type="com.example.model.User">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="email" column="email"/>
</resultMap>
<select id="getUserById" resultMap="UserResultMap">
SELECT id, name, email FROM users WHERE id = #{id}
</select>
4. List 集合
当查询结果包含多行数据时,可以使用 List
来接收结果集。这种方式适用于需要处理多条记录的情况。
示例代码:
public interface UserMapper {
List<User> getAllUsers();
}
<select id="getAllUsers" resultType="com.example.model.User">
SELECT * FROM users
</select>
5. List<Map<String, Object>>
当查询结果包含多行数据且结果集与实体类不匹配时,可以使用 List<Map<String, Object>>
来接收结果集。这种方式适用于需要灵活处理多条记录的情况。
示例代码:
public interface UserMapper {
List<Map<String, Object>> getAllUsers();
}
<select id="getAllUsers" resultType="java.util.Map">
SELECT id, name, email FROM users
</select>
6. 多参数接收
如果查询参数或结果包含了多个独立的参数,可以使用 @Param
注解来标记参数。这种方式适用于需要传递多个参数的情况。
示例代码:
public interface UserMapper {
List<User> getUsersByNameAndAge(@Param("name") String name, @Param("age") int age);
}
<select id="getUsersByNameAndAge" resultType="com.example.model.User">
SELECT * FROM users WHERE name = #{name} AND age = #{age}
</select>
7. 自定义对象
可以创建一个自定义对象来接收查询结果,特别是在结果集中包含了一些额外的信息或需要组合不同表的数据时。
示例代码:
public class UserWithDetails {
private Integer id;
private String name;
private String department;
// getters and setters
}
public interface UserMapper {
List<UserWithDetails> getUsersWithDepartment();
}
<select id="getUsersWithDepartment" resultType="com.example.model.UserWithDetails">
SELECT u.id, u.name, d.name AS department FROM users u JOIN departments d ON u.department_id = d.id
</select>
8. 动态结果类型
在某些情况下,可能需要根据运行时的情况动态决定结果类型。这时可以使用 Object
类型来接收结果,然后在应用层进行类型转换或处理。
复杂情况
1. 多表关联查询
当查询涉及到多个表的联接,并且需要将多个表的数据合并到一个对象或多个对象中时,可以使用 resultMap
和 <association>
或 <collection>
标签来定义复杂的映射关系。
示例代码
<resultMap id="ComplexUserResultMap" type="com.example.model.ComplexUser">
<id property="userId" column="user_id"/>
<result property="name" column="user_name"/>
<result property="email" column="user_email"/>
<association property="department" javaType="com.example.model.Department">
<id property="departmentId" column="department_id"/>
<result property="name" column="department_name"/>
</association>
<collection property="orders" ofType="com.example.model.Order">
<id property="orderId" column="order_id"/>
<result property="orderDate" column="order_date"/>
</collection>
</resultMap>
<select id="getComplexUser" resultMap="ComplexUserResultMap">
SELECT u.user_id, u.user_name, u.user_email,
d.department_id, d.department_name,
o.order_id, o.order_date
FROM users u
JOIN departments d ON u.department_id = d.department_id
LEFT JOIN orders o ON u.user_id = o.user_id
WHERE u.user_id = #{userId}
</select>
2. 分页查询
在需要处理大量数据并进行分页显示时,可以利用 MyBatis 的 <if>
标签动态构建 SQL 语句来实现分页功能。
示例代码
public interface UserMapper {
List<User> getUsersWithPagination(@Param("offset") int offset, @Param("limit") int limit);
}
<select id="getUsersWithPagination" resultType="com.example.model.User">
SELECT * FROM users
LIMIT #{offset}, #{limit}
</select>
3. 动态 SQL
在 SQL 语句需要根据传入的参数动态改变的情况下,可以使用 <if>
、<choose>
、<when>
、<otherwise>
、<foreach>
等标签来构建动态 SQL 语句。
示例代码
<select id="searchUsers" resultType="com.example.model.User">
SELECT * FROM users
<where>
<if test="name != null and name != ''">
AND name LIKE CONCAT('%', #{name}, '%')
</if>
<if test="age != null">
AND age = #{age}
</if>
</where>
</select>
4. 批量更新/插入
当需要批量更新或插入数据时,可以使用 <foreach>
标签来处理列表数据。
示例代码
<update id="batchUpdateStatus">
UPDATE users SET status = #{status} WHERE user_id IN
<foreach item="item" index="index" collection="ids" open="(" separator="," close=")">
#{item}
</foreach>
</update>
5. 存储过程
当需要执行复杂的数据库操作,如事务处理或批处理等,可以使用存储过程。MyBatis 支持调用存储过程并将结果映射到 Java 对象。
示例代码
<select id="callStoredProc" statementType="CALLABLE" resultType="com.example.model.User">
{ CALL get_user_data(#{userId}) }
</select>
6. 嵌套查询
在某些情况下,需要在一个查询中嵌套另一个查询来获取数据。可以使用 <select>
子标签在 <resultMap>
中定义嵌套查询。
示例代码
<resultMap id="UserWithNestedQueryResultMap" type="com.example.model.User">
<id property="userId" column="user_id"/>
<result property="name" column="user_name"/>
<association property="department" javaType="com.example.model.Department" select="selectDepartmentById"/>
</resultMap>
<select id="selectDepartmentById" resultType="com.example.model.Department">
SELECT * FROM departments WHERE department_id = #{userId}
</select>
<select id="getUserWithNestedQuery" resultMap="UserWithNestedQueryResultMap">
SELECT u.user_id, u.user_name FROM users u WHERE u.user_id = #{userId}
</select>
###3 7. 自定义类型处理器
当需要处理自定义的数据类型时,可以编写自定义类型处理器来处理特定类型的序列化和反序列化。
示例代码
public class CustomTypeHandler extends BaseTypeHandler<Date> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Date parameter, JdbcType jdbcType) throws SQLException {
ps.setTimestamp(i, new Timestamp(parameter.getTime()));
}
@Override
public Date getNullableResult(ResultSet rs, String columnName) throws SQLException {
return new Date(rs.getTimestamp(columnName).getTime());
}
@Override
public Date getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return new Date(cs.getTimestamp(columnIndex).getTime());
}
}
8. 事务管理
在处理涉及多个数据库操作的事务时,可以使用 MyBatis 的事务管理功能来确保数据的一致性。
示例代码
@Transactional
public class UserServiceImpl implements UserService {
private final UserMapper userMapper;
public UserServiceImpl(UserMapper userMapper) {
this.userMapper = userMapper;
}
@Override
public void createUser(User user) {
userMapper.insertUser(user);
// 其他操作...
}
}