我们知道,在 Mybatis 中完成单表查询是很容易的,而多表查询是 Mybatis 框架中的一个重难点,需熟练掌握。
1、多对多查询
用户和小组为多对多的关系,需求为:通过用户 id 查找其所有的小组信息
数据库设计如下:
实体类:
public class User {
private int uId;
private String uName;
private List<Group> groupList;
一个 User 对应多个 Group ,用一个 List 存储
public class Group {
private int gId;
private String gName;
private List<User> userList;
一个 User 对应多个 User,用一个 List 存储
public class UserGroup {
private User user;
private Group group;
中间表包含两个对象
实现需求:通过用户 id 查找其所有的小组信息
UserMapper 接口:
public interface UserMapper {
List<Group> getGroupByUId(int uId);
}
UserMapper.xml:
<select id="getGroupByUId" resultMap="userGroupMap">
select u.uId, u.uName, g.gId, g.gName
from `user` u,`group` g, uesr_group ug
where g.gId = ug.gId and ug.uId = #{uId} and u.uId = #{uId};
</select>
<resultMap id="userGroupMap" type="com.ssm.pojo.Group">
<id column="gId" property="gId"/>
<result column="gName" property="gName"/>
<collection property="userList" ofType="com.ssm.pojo.User">
<id column="uId" property="uId"/>
<result column="uName" property="uName"/>
</collection>
</resultMap>
由于需查询所有 Group 的信息,该方法返回 Group 集合
这里的 resutMap 类型为中间表实体对象 UserGroup ,它将两个表联系在一起
其实通过 collection 来处理集合对象的属性映射
数据库表测试数据:
查询结果(查找用户 id 为1的所有小组信息):
可以看到,小组信息以及用户信息都已经被正确地查询出来
2、 一对多查询
增加 Account 表,一个用户对应多个 Account
需求:查询指定用户所有的账户
数据库测试数据:
写法 1
实体类:
public class User {
private int uId;
private String uName;
private List<Group> groupList;
private List<Account> accountList;
一个 User 对应多个 Account,用一个 List 存储
public class Account {
private int aId;
private String aName;
private User user;
一个 Account 对应一个 User 对象
UserMapper 接口:
public interface UserMapper {
List<Group> getGroupByUId(int uId);
List<Account> getAccountByUId(int uId);
}
UserMapper 实现:
<select id="getAccountByUId" resultMap="userAccountMap">
select a.aId, a.aName, u.uId, u.uName
from user u, account a
where u.uId = a.uId and u.uId = #{uId};
</select>
<resultMap id="userAccountMap" type="com.ssm.pojo.Account">
<result column="aId" property="aId"/>
<result column="aName" property="aName"/>
<association property="user" javaType="com.ssm.pojo.User">
<result column="uId" property="uId"/>
<result column="uName" property="uName"/>
</association>
</resultMap>
查询结果:
写法1 以 Account(多的一方) 作为主表,即 resultMap 的类型为 Account,由于一个 Account 只对应一个 User,
所以在 resultMap 中 采用 assocation 引入 User,从而实现多表查询。
这种写法的特点在于结果有多行记录,将 Account 的属性直接列出,而集合中则为重复的 user 信息
写法 2
实体类:
public class User {
private int uId;
private String uName;
private List<Group> groupList;
private List<Account> accountList;
public class Account {
private int aId;
private String aName;
private int uId;
UserMapper 接口:
public interface UserMapper {
List<Group> getGroupByUId(int uId);
List<Account> getAccountByUId(int uId);
User getUserByUId(int uId);
}
该方法是通过返回 User(一对多中一的一方) ,在 User 中通过 collection 引入 Account 关联
UserMapper.xml 实现:
<select id="getUserByUId" resultMap="userAccountMap">
select a.aId, a.aName, u.uId, u.uName
from user u, account a
where u.uId = a.uId and u.uId = #{uId};
</select>
<resultMap id="userAccountMap" type="com.ssm.pojo.User">
<result column="uId" property="uId"/>
<result column="uName" property="uName"/>
<collection property="accountList" ofType="com.ssm.pojo.Account">
<result column="aId" property="aId"/>
<result column="aName" property="aName"/>
</collection>
</resultMap>
测试结果:
写法2 以 User 作为主表,即 resultMap 的类型为 User,
由于一个 User 对应多个 Account,所以在 resultMap 中 采用 collectiion 引入 Account ,从而实现多表查询。
这种写法的特点在于结果只有一行记录,将 user 的属性直接列出,而集合中则为的 Account 信息。
3、多对一查询
需求:查询给定账户对应的用户
方式 1
实体类:
public class User {
private int uId;
private String uName;
private List<Group> groupList;
private List<Account> accountList;
public class Account {
private int aId;
private String aName;
private int uId;
AccountMapper 接口:
public interface AccountMapper {
User getUserByAId(int aId);
}
这里返回 User(多对一中一的一方),在 User 中通过 collection 引入 Account
AccountMapper.xml 实现:
<select id="getUserByAId" resultMap="accountUserMap">
select u.uId, u.uName, a.aId, a.aName
from user u, account a
where u.uId = a.uId and a.aId = #{aId}
</select>
<resultMap id="accountUserMap" type="com.ssm.pojo.User">
<result column="uId" property="uId"/>
<result column="uName" property="uName"/>
<collection property="accountList" ofType="com.ssm.pojo.Account">
<result column="aId" property="aId"/>
<result column="aName" property="aName"/>
</collection>
</resultMap>
查询结果:
方式 2
实体类:
public class User {
private int uId;
private String uName;
private List<Group> groupList;
private List<Account> accountList;
public class Account {
private int aId;
private String aName;
private User user;
AccountMapper 接口:
public interface AccountMapper {
Account getAccountAndUser(int aId);
}
该方法返回 Account(多的一方),在 resultMap 中通过 association 引入 User 关联
AccountMapper.xml 实现:
<select id="getAccountAndUser" resultMap="accountUserMap">
select u.uId, u.uName, a.aId, a.aName
from user u, account a
where u.uId = a.uId and a.aId = #{aId}
</select>
<resultMap id="accountUserMap" type="com.ssm.pojo.Account">
<result column="aId" property="aId"/>
<result column="aName" property="aName"/>
<association property="user" javaType="com.ssm.pojo.User">
<result column="uId" property="uId"/>
<result column="uName" property="uName"/>
</association>
</resultMap>
测试结果:
4、总结
首先,我们要需定义好实体类的属性以及 dao 的接口
如果映射的对象只有1个,采用 assocation + javaType,如果映射的对象为一个集合 List,则采用 connection + ofType
result 标签为结果集映射关系, column 对应数据库中的列名,property 对应实体类的属性名
resultMap 的类型可以选择一对多中多的一方或一的一方,,指定好其类型后,采用 assocation + javaType 或 connection + ofType 定义好对象关联映射即可。