参考资料
一、MyBatis SQL映射文件——输入输出
学习目标:
- 掌握通过SQL映射文件进行增删改查
- 掌握参数的使用
- 掌握resultMap
1.1 SQL映射的XML文件 *Mapper.xml
SQL 映射 XML文件 的顶级标签(有前后顺序)
| 标签名 | 属性 / 描述 |
|---|---|
| mapper | 最外层标签,属性 namespace,用于指定Mapper接口类的引用位置,比如com.uni.UserMapper |
| cache | 配置给定命名空间的缓存 |
| cache-ref | 从其他命名空间引用缓存配置 |
| resultMap | 用来描述数据库结果集和对象的对应关系 |
| sql | 可以重用的SQL块,也可以被其他语句引用 |
| insert | 映射插入语句 |
| update | 映射更新语句 |
| delete | 映射删除语句 |
| select | 映射查询语句 |
1.2 mapper 标签
属性:namespace 表示命名空间
- namespace和子标签(select、insert、update等)的id 联合保证唯一,区别不同的mapper
- 绑定DAO接口
- namespace的命名必须跟某个接口同名
- 接口中的方法与映射文件中SQL语句id一一对应
<?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.uni.User">
<select id= "queryAllUser" ...>
...
</select>
</mapper>
1.3 select 标签
- select 是MyBatis中最常用的元素之一
- select 语句有很多属性可以详细配置每一条语句
| 属性 | 描述 |
|---|---|
| id | 命名空间中唯一的标识符,接口中的方法与映射文件中SQL语句一 一对应 |
| parameterType | 传入SQL语句的参数类型 |
| resultType | SQL语句返回值类型的完整类名或者别名 |
1.4 XML中获取传入的参数
查询单个用户通常是需要指定id的,比如在mysql中是这样的:
select * from user where id = 1;
所以在接口中可以这样定义方法:
UserMapper.java
public interface UserMapper{
User queryUserById(int id);
}
而在XML中如何获取到这个传入的参数呢?
这里可以通过#{} 获取这个参数,若只有一个参数,parameterType 参数可以省略不写,#{}里的内容可任意填,不过只能取一个)
#{}不能用于字符串拼接
UserMapper.xml
<!-- 根据ID查询用户 -->
<select id="queryUserById" resultType="com.uni.pojo.User">
select * from smbms_user where id = #{id}
</select>
测试:
@Test
public void testQueryUserById(){
SqlSession sqlSession = MyBatisUtil.getSession();
User user = sqlSession.getMapper(UserMapper.class).queryUserById(1);
System.out.println(user);
sqlSession.close();
}
1.4.1 多参案例(一)模糊查询
现使用 smbms_user表的username用户名和sex性别两个字段来进行模糊查询,使用到的sql语句:
select * from smbms_user where userName like CONCAT('%超%') and sex = '男';
这句话能查询带超字且性别为男的所有用户,现使用MyBatis实现,要点有:
- parameterType可不写
- 使用#{param1} 表示第一个参数
原理:
- 自动封装成Map类型的数据,key: param1 … paramN,或者参数的索引, value: 传入的参数值
- 自定义名称 @Param注解
方式一:使用param按顺序取参
UserMapper.java
List<User> queryUserLikeNameAndGender(String name, int gender);
UserMapper.xml
<!-- 根据名称和性别进行模糊查询 -->
<select id="queryUserLikeNameAndGender" resultType="com.uni.pojo.User">
select * from smbms_user where userName like CONCAT('%', #{param1}, '%') AND gender = #{param2}
</select>
方式二:使用@Param注解取参
UserMapper.java
List<User> queryUserLikeNameAndGender(@Param("userName") String name, @Param("gender") int gender);
UserMapper.xml
<select id="queryUserLikeNameAndGender" resultType="com.uni.pojo.User">
select * from smbms_user where userName like CONCAT('%', #{userName}, '%') AND gender = #{gender}
</select>
1.4.2 多参实例(二)parameterType模糊查询
paramterType参数的作用:指定SQL语句传入的参数类型
在XML中,配置了paramterType为实体类后可以使用#{实体类.成员变量}的方式来进行取值
案例:根据用户的名称和性别进行模糊查询
User.java
public class User {
private Integer id; //id
private String userName; //用户名称
private Integer gender; //性别
...
//get、set、toString() 略
}
UserMapper.java
List<User> queryUserLikeNameAndGender(User user);
UserMapper.xml
<select id="queryUserLikeNameAndGender" parameterType="com.uni.pojo.User" resultType="com.uni.pojo.User">
select * from smbms_user where userName like CONCAT('%', #{userName}, '%') AND gender = #{gender}
</select>
Test.java
public void testQueryUserLikeNameAndGender(){
SqlSession sqlSession = MyBatisUtil.getSession();
User user = new User();
user.setUserName("孙");
user.setGender(2);
List<User> users = sqlSession.getMapper(UserMapper.class).queryUserLikeNameAndGender(user);
users.forEach(u -> System.out.println(u));
sqlSession.close();
}
1.5 insert 标签
insert标签是实现sql的insert语句,所以必须指定paramterType属性,但可以没有resultType属性。
比如:
UserMapper.java
void insertUser(User user);
UserMapper.xml
<insert id="insertUser" parameter="com.uni.pojo.User">
insert into smbms_user(userCode, userName, userPassword) values(#{userCode}, #{userName}, #{userPassword})
</insert>
注:insert、update、delete标签均可以不指定 resultType属性
1.6 update 标签
主要属性:id 、parameterType
案例:修改密码
UserMapper.xml
<update id="modify" parameter="com.uni.pojo.User">
update smbms_user set userCode = #{userCode}, userName = #{userName}, userPassword=#{userPassword} where id = #{id}
</update>
1.7 delete 标签
主要属性:id、parameterType
案例:删除指定id的用户
UserMapper.xml
<delete id = "deleteUserById" parameterType="int">
delete from smbms_user where id = #{id}
</delete>
1.8 小结
-
parameterType
-
基础数据类型
- int、String、Date等
- 只能传入一个,通过#{参数名} 可获取传入的值
-
复杂数据类型
- java实体类、Map等
- 通过#{属性名} 或者 #{map的keyName}即可获取传入值
- ${} 一般很少用 (不支持占位符的时候使用)
-
-
resultType
- 返回基本类型、POJO类型
- 返回List集合,resultType还是POJO类型
- 返回Map集合,resultType还是POJO类型(不常用)
@MapKey("id") public Map<Integer, User> findUserByNameReturnMap(@Param("lastName")String lastName);- 指定返回的Map集合以id为key,也可指定对象别的属性为key
UserMapper.xml
<select id="findUserByNameReturnMap" resultType="myUser">
select * from user where username like '${lastName}'
</select>
二、MyBatis SQL 映射文件 ——复杂查询
2.1 SQL查询 - 关联表(外键关系)
现有 smbms_user 用户表和smbms_role用户角色表
用户表的userRole字段指定为用户角色表的ID

现若要显示用户信息包括角色的名称,需要用到多表查询,同样以模糊查询为例,查找姓孙而且是普通员工的SQL语句如下:
SELECT u.userName,r.roleName FROM smbms_user AS u, smbms_role AS r
WHERE u.userName LIKE CONCAT ('%', '孙', '%')
AND u.userRole = 3 AND u.userRole = r.id
此时的结果是:

除了User用户本身的信息以外,还多了一个roleName,即角色的名称,所以要想使用MyBatis框架实现多表关联,则需要将Role实体类定义在User实体类中,表示当前用户的角色信息。
2.2 对象关联
对象关联的方式有两种
- POJO之间引入聚合关系
- 一对多(1角色,多用户)
- 一对一(1订单,1用户)
- 多对一(多用户,1角色)
- 多对多(订单,产品)
- 通常在系统设计的时候设定好类之间的关系
2.3 resultType 与 resultMap
- resultType:直接表示返回类型
- 基本数据类型
- 复杂数据类型(没有关联查询时)
- resultMap:对外部resultMap的引用
- 应用场景:
- 数据库字段信息与对象属性不一致
- 复杂的联合查询,自由控制映射结果
- 应用场景:
注:resultType 与 resultMap 不能同时存在
2.4 一对多查询案例
以之前的两张表为例,一个角色可对应多个用户。
Role.java
package com.uni.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.sql.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Role {
private int id;
private String roleCode;
private String roleName;
private int createdBy;
private Date creationDate;
private int modifyBy;
private Date modifyDate;
private List<User> users;
}
User.java
package com.uni.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class User {
private Integer id; //id
private String userCode; //用户编码
private String userName; //用户名称
private Role role; // 用户角色
// ...
}
案例:查询跟当前用户相同角色的所有用户
UserMapper.java
Role queryAllUserSameRole(User user); // 查询跟当前用户相同角色的所有用户
UserMapper.xml
<!-- 查询所有的用户名称和角色名称 -->
<select id="queryAllUserSameRole" parameterType="com.uni.pojo.User" resultMap="oneRole">
SELECT u.userName,r.roleName FROM smbms_user AS u, smbms_role AS r
WHERE u.userRole = r.id AND r.id = #{userRole}
</select>
<resultMap id="oneRole" type="com.uni.pojo.Role">
<result property="roleName" column="roleName"></result>
<collection property="users" ofType="com.uni.pojo.User">
<result property="userName" column="userName"></result>
</collection>
</resultMap>
TestUserMapper.java
@Test
public void testQueryAllUserNameAndRoleName(){
SqlSession sqlSession = MyBatisUtil.getSession();
User user = new User();
user.setUserRole(3);
Role role = sqlSession.getMapper(UserMapper.class).queryAllUserSameRole(user);
for (User u : role.getUsers()) {
System.out.println(role.getRoleName() + ": " + u.getUserName());
}
sqlSession.close();
}
一对多是一个实体类对象里,比如Role角色,含有列表形式的变量用户,表示当前角色的所有用户,此时的结果应当使用<resultMap>来进行处理,将查询结果的字段作为column属性的值,与其对应的则是property属性,这个属性表示实体类里的变量名,比如在这个Demo里就是重新注入了Role角色实体类。
为什么需要用到<colection>标签呢?
因为返回的结果当中,角色名都是相同的,不同的则是用户的信息,所以要用这个标签去给成员变量List<User> user 进行注入
在这个标签里的每个<result>标签是指当前的用户。
2.5 多对一映射
-
resultMap返回的是一个引用 -
返回类型还是POJO实体类,上述Demo里是Role类
-
对象中的各个属性根据查询得到的表数据进行映射
-
id属性需要单独设置
<id>标签(提高性能),其余属性为<result>标签- property 属性指定类中的属性名,column 属性指定查询得到的表中的列名
- 多对一时,要用
<association>标签单独映射
-
可根据需求映射属性(不用每个属性都映射,比如上个Demo只映射了角色名称和用户名称)
案例:根据供应商的ID查询相关信息以及旗下所有的订单列表
Provider.java
package com.uni.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.sql.Date;
import java.util.List;
@NoArgsConstructor
@AllArgsConstructor
@Data
/* 供应商 */
public class Provider {
private Integer id;
private String proName; // 名称
// ...
}
Bill.java
package com.uni.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.sql.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Bill {
private int id;//主键ID
private String productName;//商品名称
private Provider provider; // 供应商
//...
}
ProviderMapper.java
List<Bill> queryProviderById(int id); // 查询某个供应商的所有订单
ProviderMapper.xml
<select id="queryProviderById" resultMap="oneProvider">
SELECT p.proName, b.productName FROM smbms_provider p, smbms_bill b
WHERE p.id = #{id}
</select>
<resultMap id="oneProvider" type="Bill">
<result property="productName" column="productName"></result>
<association property="provider">
<result property="proName" column="proName"></result>
</association>
</resultMap>
TestProviderMapper.java
@Test
public void queryProviderById(){
SqlSession sqlSession = MyBatisUtil.getSession();
List<Bill> bills = sqlSession.getMapper(ProviderMapper.class).queryProviderById(1);
for (Bill bill : bills)
System.out.println(bill.getProvider().getProName() + ": " + bill.getProductName());
sqlSession.close();
}
}
2.6 resultMap (多表查询)
- resultMap属性
- id:resultMap的唯一标识,不可重复
- type:java实体类
- resultMap字标签
- id:一般对应数据库中该行的主键id,设置此项可提高MyBatis的性能
- result:映射到 JavaBean的某个”简单类型“ 属性
- association: 映射到 JavaBean的某个“复杂类型”属性,比如 JavaBean类
- collection: 映射到 JavaBean的某个”复杂类型“ 属性,比如集合
关于 association 标签
-
用于复杂的类型关联,多对一、一对一(比如一个订单对应一个用户)
-
内部嵌套: 映射一个嵌套 JavaBean 属性
-
属性:
属性值 描述 property 映射数据库列的实体对象的属性 javaType 完整 Java 类名或者别名 resultMap 引用外部 resultMap -
子标签
- id
- result
- property:映射数据库列的实体对象的属性
- column: 数据库列名或者别名
关于 collection 标签
- 用于复杂类型集合,一对多
- 内部嵌套:映射一个嵌套结果集到一个列表
- 属性
| 属性值 | 描述 |
|---|---|
| property | 映射数据库列的实体对象的属性 |
| ofType | 完整 Java类名或者别名(集合所包含的类型) |
| resultMap | 引用外部resultMap |
- 子标签
- id
- result
- property:映射数据库列的实体对象的属性
- column:数据库列名或者别名
2.7 双向关联
- 如果对象之间互相都有关联关系,称之为双向关联
- 目的:任何一方都能关联到另一方
- 上述例子中的 User用户实体类 和 Role 角色实体类便是双向关联
2.8 多对多
- 数据库需要三张表关联,比如订单和商品,中间表则是订单详情表
订单 -> 产品
一个订单,多个明细
一个明细,一个产品
2.9 小结
mapper: namespace
select
- id
- parameterType
- resultType / resultMap
insert、updata、delete
- id
- parameterType
resultMap
- id
- type
- result
- association
- collection
本文深入探讨了MyBatis的SQL映射文件,包括mapper标签、select、insert、update和delete标签的使用。重点讲解了XML中如何获取传入参数,如#{param1},以及多参数查询案例。此外,文章还介绍了resultType与resultMap的区别,以及如何处理复杂查询,如一对多、多对一和多对多的关系映射。
SQL映射XML文件标签 select、insert、update | XML获取多个参数 | MyBatis实现多表查询 | resultMap标签映射&spm=1001.2101.3001.5002&articleId=122493463&d=1&t=3&u=7c27bc0bea1247babf3fdb8ef65cc2e7)
1175

被折叠的 条评论
为什么被折叠?



