我们学习了MyBatis框架的基础知识,搭建基于MyBatis框架的开发环境并初步掌握了其他使用方法,同时对MyBatis框架的核心对象和核心配置文件有了一定的了解。(如果没有了解可以去我主页看看第一章 初识MyBatis框架(2023版本IEDA)来学习)。本章继续学习MyBatis框架基本要素中的SQL映射文件,实现增、删、改及更复杂的查询操作。
2.1 SQL映射文件
在MyBatis框架中,SQL映射文件(通常是以.xml为扩展名的文件)是定义SQL语句与Java对象之间映射关系的关键部分。这些文件允许你编写SQL语句,并指定如何将结果集映射到Java对象
- SQL映射文件中的几个顶级元素介绍如下:
-
mapper: SQL映射文件的根元素。只有一个属性namespace,用于区分不同的mapper,必须全局唯一。
-
cache: 为给定命名空间配置缓存。
-
cache-ref: 引用其他命名空间中的缓存配置。
-
resultMap: 用来描述查询结果集中的字段和Java实体类属性的对应关系。
-
sql: 定义可重用的SQL语句块,可以在其他语句映射中引用,提高编写和维护SQL语句的效率。
-
insert: 映射insert语句。
-
update: 映射update语句。
-
delete: 映射delete语句。
-
select: 映射select语句。
-
注意
MyBatis框架支持面向接口的SQL映射编程,这种情况下,SQL映射文 件的开发需要注意以下规则。
(1)习惯上,SQL映射文件与该Mapper接口同名(实体类名+Mapper),并放置在同一包路径下。
(2)以要映射的Mapper接口的完全限定名(即包含包名的完整名称)作为namespace属性的值。
(3)接口中的方法名与映射文件中SQL语句映射的 ID 一 一对应。MyBatis框架通过namespace+ID确定和接口方法绑定的SQL语句。
(4)在不同的SQL映射文件中,子元素的ID可以相同。
2.2MyBatis框架的条件查询
实际项目中的查询操作通常伴随着各种条件,那么在MyBatis框架下如何为SQL语句中的查询条件赋值呢?
2.2.1实现单一条件查询
在MyBatis中实现单一条件查询通常涉及编写一个Mapper接口方法、对应的SQL映射文件(XML)中的<select>
标签以及Java实体类。下面是一个简单的示例,说明如何实现单一条件查询
1. Java实体类(User.java)
首先,你需要一个Java实体类来映射数据库中的表。例如:对于一个用户表(user),你可能有一个User类:
package com.example.domain;
public class User {
private int id;
private String name;
private String email;
// ... getter, setter, toString等方法
}
2. Mapper接口(UserMapper.java)
接下来,你需要创建一个Mapper接口来定义查询方法。例如,你可以创建一个UserMapper接口,并定义一个根据用户名查询用户的方法:
package com.example.mapper;
import com.example.domain.User;
import java.util.List;
public interface UserMapper {
// 根据用户名查询用户
User selectUserByName(String name);
// ... 其他方法
}
3. SQL映射文件(UserMapper.xml)
然后,你需要创建一个与Mapper接口相对应的SQL映射文件。在这个文件中,你将编写SQL查询语句,并指定如何将查询结果映射到Java对象。例如,你可以创建一个UserMapper.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">
<!-- 根据用户名查询用户 -->
<select id="selectUserByName" parameterType="string" resultType="com.example.domain.User">
SELECT * FROM users WHERE name = #{name}
</select>
<!-- ... 其他SQL语句 -->
</mapper>
在上面的<select>
标签中,id属性与Mapper接口中的方法名相对应,parameterType指定了传递给SQL语句的参数类型(这里是字符串),而resultType则指定了查询结果的映射类型(这里是User类的完全限定名)
4. 配置MyBatis
最后,你需要在MyBatis的配置文件(如mybatis-config.xml)中指定SQL映射文件的位置,或者如果你使用的是Spring框架,你可以在Spring的配置文件中进行配置。以下是在MyBatis配置文件中指定映射文件的一个示例:
<configuration>
<!-- ... 其他配置 ... -->
<mappers>
<mapper resource="com/example/mapper/UserMapper.xml"/>
<!-- ... 其他映射文件 ... -->
</mappers>
<!-- ... 其他配置 ... -->
</configuration>
MyBatis框架内建的部分别名与Java数据类型的映射关系
别名 | 映射的类型 | 别名 | 映射的类型 |
---|---|---|---|
boolean | Boolean | string | String |
byte | Byte | bigdecimal或decimal | BigDecimal |
long | Long | date | Date |
short | Short | map | Map |
int或integer | Integer | hashmap | HashMap |
double | Double | list | List |
float | Float | arraylist | ArrayList |
注意
有关MyBatis框架内建别名的更多内容,可以参考MyBatis框架用户手册的“3.1.3 typeAliases”一节。
2.2.2实现多条件查询
在实际应用中,数据查询经常会综合多种条件,对于多条件查询,MyBatis框架提供了多种方法实现条件赋值。它允许你直接使用 XML 文件或注解来配置和映射原生 SQL、存储过程以及高级映射。下面是如何使用 MyBatis 实现多条件查询的一个示例:
首先,假设你有一个 User 表,并且你想根据用户名(username)、邮箱(email)和年龄(age)等字段进行查询
- 定义 Mapper 接口
在你的 Mapper 接口中,你可以定义一个方法来执行多条件查询。
public interface UserMapper {
List<User> selectUsersByConditions(@Param("username") String username,
@Param("email") String email,
@Param("age") Integer age);
}
注意这里使用了 @Param 注解来指定参数名,这样你就可以在 XML 映射文件中引用这些参数了
- 编写 XML 映射文件
在 MyBatis 的 XML 映射文件中,你可以使用动态 SQL(<if>
标签)来实现多条件查询
<mapper namespace="com.example.mapper.UserMapper">
<select id="selectUsersByConditions" resultType="com.example.domain.User">
SELECT * FROM user
WHERE 1 = 1
<if test="username != null and username != ''">
AND username = #{username}
</if>
<if test="email != null and email != ''">
AND email = #{email}
</if>
<if test="age != null">
AND age = #{age}
</if>
</select>
</mapper>
注意这里使用了 WHERE 1 = 1 作为条件查询的起始点,这样即使所有的 <if>
条件都不满足,查询也不会因为缺少 WHERE 子句而报错
- 在Service 或 Controller 中调用 Mapper 方法
现在你可以在你的 Service 或 Controller 中调用 UserMapper 的 selectUsersByConditions 方法来执行多条件查询了
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public List<User> getUsersByConditions(String username, String email, Integer age) {
return userMapper.selectUsersByConditions(username, email, age);
}
}
然后你就可以在你的 Controller 或其他需要的地方调用 UserService 的 getUsersByConditions 方法了。
这样,你就可以使用 MyBatis 实现多条件查询了。根据具体需求,你可以进一步扩展和优化这个查询
1.将查询条件封装成Java对象作为入参
在MyBatis中,你可以将查询条件封装成一个Java对象,然后将其作为Mapper方法的参数。这样做的好处是,你可以更方便地管理多个查询条件,并且可以让代码更加清晰和易于维护
我来举一个例子:
- 定义查询条件对象:
首先,定义一个包含查询条件的Java对象(DTO,Data Transfer Object)
public class UserQueryDTO {
private String username;
private String email;
private Integer age;
// Getters方法和setters方法
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
- 修改Mapper接口
在Mapper接口中,将方法的参数更改为你的查询条件对象
public interface UserMapper {
List<User> selectUsersByConditions(UserQueryDTO queryDTO);
}
- 编写XML映射文件
在MyBatis的XML映射文件中,你可以像之前一样使用动态SQL,但是这次你将从queryDTO对象中引用参数
<mapper namespace="com.example.mapper.UserMapper">
<select id="selectUsersByConditions" resultType="com.example.domain.User">
SELECT * FROM user
<where>
<if test="queryDTO.username != null and queryDTO.username != ''">
AND username = #{queryDTO.username}
</if>
<if test="queryDTO.email != null and queryDTO.email != ''">
AND email = #{queryDTO.email}
</if>
<if test="queryDTO.age != null">
AND age = #{queryDTO.age}
</if>
</where>
</select>
</mapper>
注意这里使用了<where>
元素,它可以智能地处理开头的AND或OR,使得在没有任何条件被添加时不会包含额外的WHERE子句
- 在Service或Controller中调用Mapper方法
现在,你可以在你的Service或Controller中创建一个UserQueryDTO对象,设置查询条件,然后调用Mapper方法
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public List<User> getUsersByConditions(UserQueryDTO queryDTO) {
return userMapper.selectUsersByConditions(queryDTO);
}
}
现在,你的代码更加清晰,并且查询条件被封装在一个单独的Java对象中,这使得它们更容易被管理和使用
2.将查询条件封装成Map对象作为入参
在MyBatis中,除了将查询条件封装成Java对象(DTO)作为入参外,你还可以选择使用Map对象来传递查询条件。这样做在某些场景下可能更加灵活,尤其是当你不需要为每一个查询条件都创建一个DTO类。
以下使用Map对象作为查询条件入参:
- 在Mapper接口中定义方法
Mapper接口的方法现在将接收一个Map<String, Object>
类型的参数
public interface UserMapper {
List<User> selectUsersByConditions(Map<String, Object> params);
}
- 编写XML映射文件
在XML映射文件中,你可以直接通过#{paramName}的形式来引用Map中的参数。
<mapper namespace="com.example.mapper.UserMapper">
<select id="selectUsersByConditions" resultType="com.example.domain.User">
SELECT * FROM user
<where>
<if test="params.username != null and params.username != ''">
AND username = #{params.username}
</if>
<if test="params.email != null and params.email != ''">
AND email = #{params.email}
</if>
<if test="params.age != null">
AND age = #{params.age}
</if>
</where>
</select>
</mapper>
- 在Service或Controller中调用Mapper方法
现在,在你的Service或Controller中,你可以创建一个Map对象,设置查询条件,然后调用Mapper方法
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public List<User> getUsersByConditions(String username, String email, Integer age) {
Map<String, Object> params = new HashMap<>();
params.put("username", username