年轻的时候,遇见了一个人,便以为余生再没有江湖,后来,才懂,她才是江湖的起源。

上一章简单介绍了MyBatis的一对多映射(九),如果没有看过,​​请观看上一章​​。

一. Mybatis的多对多关联映射

多对多的关系在数据库中是很常见的,但是在业务代码中常常处理成 双向的一对多的关联。 可以与Hibernate的多对多对照来看:
​Hibernte的多对多映射(十二)​​

创建User表:

MyBatis的多对多映射(十)_MyBatis人多对多

创建Role 角色表:

MyBatis的多对多映射(十)_java_02

创建User_role 表

MyBatis的多对多映射(十)_一对多_03

相应的实体类:

User.java

package com.yjl.pojo;

import java.util.List;

/**
@author:yuejl
@date: 2019年6月15日 上午11:11:02
@Description Mybatis 使用的基本类 User
*/
public class User {
/**
* @param id id编号,自增
* @param name 姓名
* @param age 年龄
* @param sex 性别
* @param description 描述
*/
private Integer id;
private String name;
private Integer age;
private String sex;
private String description;
//引入角色的多个对象集合。。
private List<Role> roles;
public User(){

}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", age=" + age + ", sex=" + sex + ", description=" + description
+ "]";
}
}

Role.java

package com.yjl.pojo;

import java.util.List;

/**
@author:两个蝴蝶飞
@date: 2019年3月2日 下午6:18:51
@Description 角色组
*/
public class Role {
/**
* @param id 角色编号
* @param name 用户的名称
*/
private Integer id;
private String name;
public Role() {
}
public Role(String name) {
this.name = name;
}
/**
* @param users 用户 是一对多的关系
*/
private List<User> users;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
@Override
public String toString() {
return "Role [id=" + id + ", name=" + name + "]";
}
}

二. 角色到员工的一对多查询(select 形式)

RoleMapper.java 中接口:

public Role findByIdWithSelect(int id);

UserMapper.java 中接口:

public List<User> findUserByRoleId(@Param(value="roleId") int roleId);

RoleMapper.xml sql语句:

<!--角色查询员工的一对多-->
<resultMap type="role" id="roleResultMapWithSelect">
<id property="id" column="id"/>
<result property="name" column="name"/>
<collection property="users" ofType="user" column="id"
select="com.yjl.mapper.UserMapper.findUserByRoleId"></collection>
</resultMap>

<select id="findByIdWithSelect" parameterType="int" resultMap="roleResultMapWithSelect">
select * from role t where t.id=#{id}
</select>

UserMapper.xml 中sql语句

<resultMap type="user" id="userResultMap">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sex" column="sex"/>
<result property="age" column="age"/>
<result property="description" column="description"/>
</resultMap>
<select id="findUserByRoleId" parameterType="int" resultMap="userResultMap">
select u.* from user_role t,user u where t.userId=u.id and t.roleId=#{roleId}
</select>

测试方法:

@Test
public void findByIdWithSelectTest(){
SqlSession sqlSession=SqlSessionFactoryUtils.getSession();
RoleMapper roleMapper=sqlSession.getMapper(RoleMapper.class);
//具有超级管理员角色的用户
Role role=roleMapper.findByIdWithSelect(1);
System.out.println(role);
List<User> userList=role.getUsers();
userList.forEach(n ->System.out.println(n));
}

MyBatis的多对多映射(十)_一对多_04

三. 员工到角色的一对多的嵌套select 查询

UserMapper.java 接口:

public User getByIdWithSelect(int id);

RoleMapper.java 接口:

public List<Role> findRoleByUserId(@Param(value="userId") int userId);

UserMapper.xml sql语句:

<resultMap type="user" id="userResultMapWithSelect">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sex" column="sex"/>
<result property="age" column="age"/>
<result property="description" column="description"/>
<collection property="roles" ofType="role" column="id"
select="com.yjl.mapper.RoleMapper.findRoleByUserId"></collection>
</resultMap>
<!-- 嵌套select -->
<select id="getByIdWithSelect" parameterType="int" resultMap="userResultMapWithSelect">
select * from user where id=#{id}
</select>

RoleMapper.xml 中sql语句:

<resultMap type="role" id="roleResultMap">
<id property="id" column="id"/>
<result property="name" column="name"/>
</resultMap>
<select id="findRoleByUserId" parameterType="int" resultMap="roleResultMap">
select r.* from user_role t,role r where t.roleId=r.id and t.userId=#{userId}
</select>

测试方法:

@Test
public void getByIdWithSelectTest(){
SqlSession sqlSession=SqlSessionFactoryUtils.getSession();
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
//查询该员工所具有的角色
User user=userMapper.getByIdWithSelect(1);
System.out.println(user);
List<Role> roleList=user.getRoles();
roleList.forEach(n ->System.out.println(n));
}

MyBatis的多对多映射(十)_java_05

四. user 到role 的嵌套结果 查询

UserMapper.java 接口

public User getByIdWithResult(int id);

UserMapper.xml sql

<resultMap type="user" id="userResultMapWithResult">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sex" column="sex"/>
<result property="age" column="age"/>
<result property="description" column="description"/>
<collection property="roles" javaType="ArrayList" ofType="role">
<id property="id" column="rid"/>
<result property="name" column="rname"/>
</collection>
</resultMap>
<!-- 用具体的语句,而不是 * 这样的。 -->
<select id="getByIdWithResult" parameterType="int" resultMap="userResultMapWithResult">
select u.*,r.id as rId,r.name as rname from user u,role r ,user_role ur where u.id=ur.userId and r.id=ur.roleId
and ur.userId=#{id}
</select>

测试方法:

@Test
public void getByIdWithResultTest(){
SqlSession sqlSession=SqlSessionFactoryUtils.getSession();
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
User user=userMapper.getByIdWithResult(1);
System.out.println(user);
List<Role> roleList=user.getRoles();
roleList.forEach(n ->System.out.println(n));
}

MyBatis的多对多映射(十)_java_06

可以发现,多对多实际上就是两个一对多的关系。 完全按照一对多的模式进行做。

但是一般,员工和角色表时不但会有userId,roleId, 还常常会有 created_by,created_time, 即创建人和创建时间等字段,这个时候就不能用上面的方式, 需要引入另外一个实体 UserRole 实体, 转换成两个一对多的关系, User与UserRole 是一对多的关系,Role 与UserRole 也是一对多的关系。

五. UserRolee 实体类的两个一对多关联

User 表 和Role 表,保持不变。

对UserRole 表,添加两个字段。

MyBatis的多对多映射(十)_java_07

那么User.java 实体类就改变成了:

package com.yjl.pojo;

import java.util.List;

/**
@author:yuejl
@date: 2019年6月15日 上午11:11:02
@Description Mybatis 使用的基本类 User
*/
public class User {
/**
* @param id id编号,自增
* @param name 姓名
* @param age 年龄
* @param sex 性别
* @param description 描述
*/
private Integer id;
private String name;
private Integer age;
private String sex;
private String description;
//引入员工角色的多个对象集合。。
private List<UserRole> userRole;
public User(){

}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public List<UserRole> getUserRole() {
return userRole;
}
public void setUserRole(List<UserRole> userRole) {
this.userRole = userRole;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", age=" + age + ", sex=" + sex + ", description=" + description
+ "]";
}
}

其中的 Role.java 变成了:

package com.yjl.pojo;

import java.util.List;

/**
@author:两个蝴蝶飞
@date: 2019年3月2日 下午6:18:51
@Description 角色组
*/
public class Role {
/**
* @param id 角色编号
* @param name 用户的名称
*/
private Integer id;
private String name;
public Role() {
}
public Role(String name) {
this.name = name;
}
/**
* @param userRole 用户角色实体 是一对多的关系
*/
private List<UserRole> userRole;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<UserRole> getUserRole() {
return userRole;
}
public void setUserRole(List<UserRole> userRole) {
this.userRole = userRole;
}
@Override
public String toString() {
return "Role [id=" + id + ", name=" + name + "]";
}
}

新增加一个UserRole.java 类:

package com.yjl.pojo;

import java.util.Date;

/**
@atuhor:yuejl
@Description: 类描述
*/
public class UserRole {
private User user;
private Role role;
private String created_by;
private Date created_date;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
public String getCreated_by() {
return created_by;
}
public void setCreated_by(String created_by) {
this.created_by = created_by;
}
public Date getCreated_date() {
return created_date;
}
public void setCreated_date(Date created_date) {
this.created_date = created_date;
}
@Override
public String toString() {
return "UserRole [user=" + user + ", role=" + role + ", created_by=" + created_by + ", created_date="
+ created_date.toLocaleString() + "]";
}
}

六. 员工去查询角色

UserMapper.java 的接口:

public User getUserRoleById(int id);

UserMapper.xml sql语句:

<resultMap type="user" id="userResultMapWithUserRole">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sex" column="sex"/>
<result property="age" column="age"/>
<result property="description" column="description"/>
<!--引入集合为userRole的集合-->
<collection property="userRole" javaType="ArrayList" ofType="userRole"
column="id" select="com.yjl.mapper.UserRoleMapper.findByUserId">
</collection>
</resultMap>

<select id="getUserRoleById" parameterType="int" resultMap="userResultMapWithUserRole">
select * from user where id=#{id}
</select>

UserRoleMapper.java 的接口为:

package com.yjl.mapper;

import org.apache.ibatis.annotations.Param;

import com.yjl.pojo.UserRole;

/**
@atuhor:yuejl
@Description: 类描述
*/
public interface UserRoleMapper {
public UserRole findByUserId(@Param(value="userId") int userId);
}

UserRoleMapper.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.yjl.mapper.UserRoleMapper">
<resultMap type="userRole" id="userRoleMap">
<result property="created_by" column="created_by" javaType="string"/>
<result property="created_date" column="created_date" javaType="date"/>
<!-- 关联一下,相应的角色信息,为一对一的形式 -->
<association property="role" javaType="role" column="roleId"
select="com.yjl.mapper.RoleMapper.findById"></association>
</resultMap>

<select id="findByUserId" parameterType="int" resultMap="userRoleMap">
select t.* from user_role t where t.userId=#{userId}
</select>
</mapper>

RoleMapper.java 的接口为:

public Role findById(int id);

RoleMapper.xml 的sql语句为:

<resultMap type="role" id="roleResultMap">
<id property="id" column="id"/>
<result property="name" column="name"/>
</resultMap>

<select id="findById" parameterType="int" resultMap="roleResultMap">
select * from role t where t.id=#{id}
</select>

测试方法:

@Test
public void getUserRoleByIdTest(){
SqlSession sqlSession=SqlSessionFactoryUtils.getSession();
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
//查询该员工所具有的角色
User user=userMapper.getUserRoleById(1);
List<UserRole> roleList=user.getUserRole();
System.out.println(user);
for (UserRole userRole : roleList) {
System.out.println("输出创建人:"+userRole.getCreated_by());
System.out.println("输出创建日期:"+userRole.getCreated_date());
Role role=userRole.getRole();
System.out.println(role);
}
}

MyBatis的多对多映射(十)_MyBatis人多对多_08

这是员工找角色的,也可以角色去找员工。 与上面的思路差不多,就不讲解了。 当然,也有对应的result 的形式。

UserMapper.java 接口:

public User getUserRoleByIdWithResult(int id);

UserMapper.xml sql语句:

<resultMap type="user" id="userResultMapWithUserRoleResult">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sex" column="sex"/>
<result property="age" column="age"/>
<result property="description" column="description"/>
<collection property="userRole" ofType="userRole" javaType="arrayList">
<result property="created_by" column="created_by" javaType="string"/>
<result property="created_date" column="created_date" javaType="date"/>
<!-- 对角色的一对一 -->
<association property="role" javaType="role">
<id property="id" column="rId" javaType="int"/>
<result property="name" column="rName" javaType="string"/>
</association>
</collection>
</resultMap>
<select id="getUserRoleByIdWithResult" parameterType="int" resultMap="userResultMapWithUserRoleResult">
select u.id as id,u.name as name,u.sex as sex,u.age as age,u.description as description,
ur.created_by as created_by,ur.created_date as created_date,
r.id as rId,r.name as rName,
ur.userId as userId,ur.roleId as roleId from user u,role r,user_role ur where u.id=ur.userId and r.id=ur.roleId
and u.id=#{id}
</select>

测试方法:

@Test
public void getUserRoleByIdWithResultTest(){
SqlSession sqlSession=SqlSessionFactoryUtils.getSession();
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
//查询该员工所具有的角色
User user=userMapper.getUserRoleByIdWithResult(1);
List<UserRole> roleList=user.getUserRole();
System.out.println(user);
System.out.println("长度是:"+roleList.size());
for (UserRole userRole : roleList) {
System.out.println("输出创建人:"+userRole.getCreated_by());
System.out.println("输出创建日期:"+userRole.getCreated_date());
Role role=userRole.getRole();
System.out.println(role);
}
}

查询的时候,会发现只查询出一条数据。

MyBatis的多对多映射(十)_一对多_09

显示的是查询出3条,为什么只显示一条呢? 查了很多资料,最后发现可能跟数据有关。 user 表中的数据是一样的,给处理成了一条,那么 userrole 表中的数据也是一样的,也可以被处理成了一条。 故改变userrole 表中的数据。

MyBatis的多对多映射(十)_MyBatis人多对多_10

这个时候,运行为:

MyBatis的多对多映射(十)_一对多_11

将userrole 中的数据再次改变,使其中有相同的。

MyBatis的多对多映射(十)_java_12

再次运行为:

MyBatis的多对多映射(十)_一对多_13

故可知,与数据是否相同有很大的关系。 如果实例化的数据都一样,MyBatis会将其当成一个对象,不会再重新初始化。

谢谢!!!