一、 单表查询
根据用户id查询用户信息的功能
Controller 实现代码如下:
@RequestMapping("/getuser")
public User getUserById(Integer id){
return userService.getUserById(id);
}
Mapping.xml 实现代码如下:
<select id="getUserById" resultType="com.example.demo.User">
select * from userinfo where id=#{id}
</select>
二、 参数占位符 #{} 和 ${}
#{} 预编译处理:
MyBatis 在处理#{}时,会将SQL中的#{}替换为 ?号,
使用PreparedStatement的Set方法来赋值
${} 字符直接替换:
是MyBatis 在处理 ${} 时,就是把 ${} 替换成变量的值
适用场景:业务需要传递SQL命令只能使用${}
注意:
1.${}可以实现排序查询,使用 #{sort} 就不能实现排序查询了,
因为当使用 #{sort}查询时,如果传递的值为String 会加单引号,就会导致 sql错误。
2.如果要使用${},传递的参数一定要能被穷举,否则不可使用
三、like查询
XML配置方式:
<!-- Mapper XML -->
<select id="getUserByUsername" parameterType="String" resultType="User">
SELECT * FROM user WHERE username LIKE '%' || ${username} || '%'
</select>
使用 '%' || ${username} || '%' 来构建动态的 LIKE 查询条件,
其中 || 用于字符串的连接操作,上述 语句是存在SQL注入风险的,只有在特定情况下,确保参数安全性,并且需要动态构建SQL语句时才考虑使用 ${}
用 #{}来解决SQL注入问题:
<!-- Mapper XML -->
<select id="getUserByUsername" parameterType="String" resultType="User">
SELECT * FROM user WHERE username LIKE CONCAT('%', #{username}, '%')
</select>
使用 LIKE CONCAT('%', #{username}, '%') 将参数值与SQL语句进行拼接,确保了参数的安全性,来构建模糊查询的条件。
其中 % 表示通配符,可以匹配任意字符,例如 %keyword% 表示在任意位置匹配关键字
Mapper 接口:
// Mapper 接口
public interface UserDao {
List<User> getUserByUsername(@Param("username") String username);
}
// Mapper XML 中不需要额外配置
四、 返回类型:resultType
绝大数查询场景可以使用resultType进行返回,如下代码所示:
<!-- 查询单个基本类型 -->
<select id="getTotalCount" resultType="int">
SELECT COUNT(*) FROM users
</select>
<!-- 查询结果为Java字符串类型 -->
<select id="getRecordCount" resultType="java.lang.String">
SELECT COUNT(*) FROM records
</select>
<!-- 查询单个简单对象 -->
<select id="getUserById" resultType="com.example.User">
SELECT id, username, email FROM users WHERE id = #{id}
</select>
<!-- 查询复杂对象 -->
<select id="getUserOrder" resultType="com.example.UserOrder">
SELECT u.id, u.username, o.order_number
FROM users u JOIN orders o ON u.id = o.user_id
WHERE u.id = #{userId}
</select>
<!-- 查询结果存储在集合中 -->
<select id="getAllUsers" resultType="java.util.List">
SELECT id, username, email FROM users
</select>
优点:使用方便,可以直接定义到某个实体类
注意:需要注意的是,当使用 resultType 时,MyBatis 假设查询结果与指定的类型完全匹配。如果查询结果的列名与对象的属性名不完全一致,或者需要进行更复杂的结果映射,你可以考虑使用 resultMap 进行手动映射。
4.1 返回字典映射:resultMap
resultMap 使用场景:
字段名称与程序中的属性名不同的情况,可使用resultMap配置映射;
一对一和一对多关系可以使用resultMap映射并查询数据。
字段名和属性名不同的情况:
程序中的属性如下:
这个时候使用resultMap
mapper.xml 代码如下:
<resultMap id="BaseMap" type="com.example.demo.model.User">
<id column="id" property="id"> </id>
<result column="username" property="username"></result>
<result column="pasword" property="pwd"></result>
</resultMap>
<select id="getUserById" resultMap="BaseMap">
select * from userinfo where id=#{id}
</select>
五、 多表查询 ( 使用@Results 注解的方式)
一对一关系:
一对一关系指的是两个表之间存在唯一的关联关系,其中一个表的一条记录对应另一个表的一条记录。在数据库中,通常使用外键来建立一对一关系。
示例案例:
假设有两个表:user 和 user_profile。每个用户只有一个用户资料。这里,user 表包含用户的基本信息,user_profile 表包含用户的详细资料。这两个表通过 user_id 字段建立了一对一关系。
CREATE TABLE user (
id INT PRIMARY KEY,
username VARCHAR(50),
...
);
CREATE TABLE user_profile (
id INT PRIMARY KEY,
user_id INT UNIQUE,
full_name VARCHAR(100),
...
);
在 MyBatis 中,可以使用一对一关系进行联合查询,并将结果映射到一个对象中。以下是一个示例:
public class User {
private int id;
private String username;
private UserProfile profile;
// getter and setter methods
}
public class UserProfile {
private int id;
private int userId;
private String fullName;
// getter and setter methods
}
<!-- Mapper 接口 -->
public interface UserMapper {
@Select("SELECT u.id, u.username, p.id as 'profile.id', p.full_name as 'profile.fullName' " +
"FROM user u " +
"JOIN user_profile p ON u.id = p.user_id " +
"WHERE u.id = #{userId}")
@Results({
@Result(property = "id", column = "id"),
@Result(property = "username", column = "username"),
@Result(property = "profile.id", column = "profile.id"),
@Result(property = "profile.fullName", column = "profile.fullName")
})
User getUserWithProfileById(@Param("userId") int userId);
}
在上述,User类代表用户,UserProfile 类代表用户资料,User类中包含一个UserProfile对象用于表示一对一关系
在UserMapper接口中,使用联合查询语句将user表与user_profile表连在一起,并使用@Results注释进行结果映射,
通过指定每个属性的映射关系,将查询结果正确的映射到User对象及其关联的UserProfile对象中。
一对多关系:
一对多关系指的是两个表之间存在一个对多关系,其中一个表的一条记录对应另一个表的多条记录。在数据库中,通常使用外键来建立一对多关系。
示例案例:
假设有两个表:department 和 employee。每个部门可以有多个员工。这里,department 表包含部门的信息,employee 表包含员工的信息,并通过 department_id 字段建立了一对多关系
CREATE TABLE department (
id INT PRIMARY KEY,
name VARCHAR(50),
...
);
CREATE TABLE employee (
id INT PRIMARY KEY,
name VARCHAR(50),
department_id INT,
...
);
在MyBatis中,可以使用一对多关系进行联合查询,并将结果映射到一个对象中,其中一个对象包含一个集合来表示多的一方,以下为示例:
public class Department {
private int id;
private String name;
private List<Employee> employees;
// getter and setter methods
}
public class Employee {
private int id;
private String name;
// getter and setter methods
}
Department 类代表部门,Employee 类代表员工。Department 类中包含一个 List 对象用于表示一对多关系。
<!-- Mapper 接口 -->
public interface DepartmentMapper {
@Select("SELECT d.id, d.name, e.id as 'employees.id', e.name as 'employees.name' " +
"FROM department d " +
"LEFT JOIN employee e ON d.id = e.department_id " +
"WHERE d.id = #{departmentId}")
@Results({
@Result(property = "id", column = "id"),
@Result(property = "name", column = "name"),
@Result(property = "employees", column = "id", javaType = List.class, many = @Many(select = "getEmployeesByDepartmentId"))
})
Department getDepartmentWithEmployeesById(@Param("departmentId") int departmentId);
@Select("SELECT id, name FROM employee WHERE department_id = #{departmentId}")
List<Employee> getEmployeesByDepartmentId(@Param("departmentId") int departmentId);
}
在 DepartmentMapper 接口中,使用联合查询语句将 department 表和 employee 表连接在一起,并使用 @Results 注解进行结果映射。通过指定每个属性的映射关系,将查询结果正确地映射到 Department 对象及其关联的员工集合中。
另外,通过在 @Results 注解中指定 javaType = List.class 和 many = @Many,将 getEmployeesByDepartmentId 方法与 employees 属性建立关联,并在该方法中查询指定部门的所有员工。
这样,在调用 getDepartmentWithEmployeesById 方法时,将返回一个 Department 对象,其中包含部门的信息和关联的员工列表。
总结:
一对一和一对多关系是多表查询中常见的关系类型。使用 MyBatis 可以方便地处理这些关系,通过正确的结果映射,可以将查询结果准确地映射到相应的对象及其关联对象中。
六、一对一 MyBatis注解的方式实现多表查询
使用 MyBatis 注解方式实现多表查询可以通过以下步骤进行:
定义结果对象(POJO):首先,你需要定义一个结果对象来保存多表查询的结果。该对象应该包含你想要从多个表中检索的字段,并提供相应的 getter 和 setter 方法。
编写 SQL 查询语句:使用注解方式,你可以在 Mapper 接口的方法上直接编写 SQL 查询语句。在查询语句中,可以使用 JOIN 操作符来连接多个表,并选择需要的字段。
声明方法和参数:在 Mapper 接口中声明一个方法,并使用注解来指定对应的 SQL 查询语句和参数。方法的返回类型应该与结果对象一致,或者是结果对象的集合。
案例展示:
// 结果对象
public class UserOrder {
private int userId;
private String username;
private String orderNumber;
// 其他属性和对应的 getter/setter 方法
}
// Mapper 接口
@Mapper
public interface UserDao {
@Select("SELECT u.user_id, u.username, o.order_number " +
"FROM user u " +
"JOIN orders o ON u.user_id = o.user_id " +
"WHERE u.user_id = #{userId}")
UserOrder getUserOrderById(@Param("userId") int userId);
}
上述示例中,
1.定义结果对象UserOrder,包含userId,username,orderNumber等属性,提供相应的getter与setter方法
2.Mapper接口中使用@Select 注解编写了一个SQL查询语句,使用JOIN操作符连接了user表与orders表,并选择了需要的字段
3.最后声明方法getUserOrderById,并使用@Param注解来指定方法参数与SQL查询语句中参数的对应关系
通过以上步骤,你就可以使用注解方式实现多表查询,并通过调用相应的方法获取查询结果
resultMap手动映射查询结果:
通过定义 resultMap,你可以明确指定查询结果与对象属性之间的映射关系,以及进行一些高级的结果处理。
- 指定查询结果与对象属性的映射关系:你可以定义每个属性与查询结果列之间的映射关系,包括列名、属性名、类型转换等。
- 处理复杂的结果映射:当查询结果与对象的结构不完全匹配时,你可以使用
resultMap 进行复杂的结果映射,例如嵌套对象、一对多关系等。
3.执行高级的结果处理逻辑:你可以在
resultMap 中定义一些高级的结果处理逻辑,例如使用自定义的类型处理器、使用 SQL 函数进行计算、调用对象的方法等。
下面是案例:
<!-- Mapper XML -->
<resultMap id="userResultMap" type="com.example.User">
<id property="id" column="user_id" />
<result property="username" column="user_name" />
<result property="email" column="user_email" />
</resultMap>
<select id="getUserByUsername" parameterType="String" resultMap="userResultMap">
SELECT user_id, user_name, user_email FROM user WHERE username LIKE CONCAT('%', #{username}, '%')
</select>
首先定义了一个名为 userResultMap 的 resultMap,类型为com.example.User
resultMap 中定义每个属性与查询结果列之间的映射关系,
使用property属性指定对象属性,使用column属性指定查询结果列(指定数据库列的属性名称)
最后,在查询语句中使用 resultMap="userResultMap" 指定使用该 resultMap 进行结果映射。
使用 resultMap 进行手动映射可以更加灵活地处理查询结果,尤其是在复杂的映射关系和结果处理逻辑时。