Mybatis对于多对多关系下的查询提供了集合(collection)的概念来解决,collection属性是resultMap高级结果映射的子集,首先,在本例中我们使用的是集合元素来解决多对多的查询。 然后你会注意到有一个新的 “ofType” 属性。这个属性非常重要,它用来将 JavaBean(或字段)属性的类型和集合存储的类型区分开来。在集合中ofType指的是集合中元素的类型。

  首先介绍一下Demo情况:

  • 实体类:User(用户)类和Role(角色)类,类中的属性在后面代码中贴出
  • 关系:一个用户可以有多个角色,一个角色可以赋予多个用户中
  • 数据库表结构:用户表、角色表、中间表(用于存储用户和角色的关系)
  • 本例中实现查询的目标:查询用户时同时获取用户所拥有的角色的信息(当查询角色时同时获取角色所属用户的信息的情况和下面的例子原理一样,主要是修改select中的sql语句)

  1.用户实体类以及角色实体类

public class User implements Serializable{
private Integer id;
private String username;
private Date birthday;
private String sex;
private String address;
private List<Role> roles; get和set方法省略 ......
}
public class Role implements Serializable{
private Integer roleId;
private String roleName;
private String roleDesc;
private List<User> users;
get和set方法省略 ......
}

  这里主要是增加用户所拥有的角色的List属性和角色所属用户的List属性,后面做resultMap结果映射的时候使用。

  2.数据库表结构

DROP TABLE IF EXISTS user;
CREATE TABLE user (
id INT(11) NOT NULL auto_increment,
username VARCHAR(32) NOT NULL COMMENT '用户名称',
birthday datetime default NULL COMMENT '生日',
sex char(1) default NULL COMMENT '性别',
address varchar(256) default NULL COMMENT '地址',
PRIMARY KEY (id)
)ENGINE=InnoDB default CHARSET=utf8
INSERT INTO `user` VALUES ('41', '老王', '2018-02-27 17:47:08', '男', '石家庄');
INSERT INTO `user` VALUES ('45', '老李', '2018-02-27 17:47:08', '男', '石家庄');
INSERT INTO `user` VALUES ('46', '老郭', '2018-02-27 17:47:08', '男', '石家庄');
INSERT INTO `user` VALUES ('47', 'mde', '2019-06-26 15:04:25', '女', '河南');
INSERT INTO `user` VALUES ('48', 'nan', '2019-08-01 15:04:54', '女', '合肥'); DROP TABLE IF EXISTS role;
CREATE TABLE role(
ID int(11) NOT NULL COMMENT '编号',
ROLE_NAME VARCHAR(30) DEFAULT NULL COMMENT '角色名称',
ROLE_DESC VARCHAR(60) DEFAULT NULL COMMENT '角色描述',
PRIMARY KEY (ID)
)ENGINE=INNODB DEFAULT CHARSET=utf8 INSERT INTO role (ID,ROLE_NAME,ROLE_DESC) VALUES (1,'院长','管理整个学院'),(2,'总裁','管理整个公司'),(3,'校长','管理整个学校'); DROP TABLE IF EXISTS user_role;
CREATE TABLE user_role(
UID int(11) NOT NULL COMMENT '用户编号',
RID INT(11) NOT NULL COMMENT '角色编号',
PRIMARY KEY (UID,RID),
CONSTRAINT FK_Reference_10 FOREIGN KEY(RID) REFERENCES role(ID),
CONSTRAINT FK_Reference_9 FOREIGN KEY(UID) REFERENCES user(id)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO user_role(UID,RID) VALUES(41,1),(45,1),(41,2);

这里主要是增加了中间表。

  3.在UserDao接口中声明查询所有用户的方法findAll();

    /**
* 查询所有的用户同时查询出所拥有的角色的信息
*
* @return
*/
List<User> findAll();

  4.在UserDao.xml中配置findAll()方法

<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.dao.UserDao">
<resultMap id="userMap" type="com.example.domain.User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="birthday" column="birthday"/>
<result property="sex" column="sex"/>
<result property="address" column="address"/>
<collection property="roles" ofType="com.example.domain.Role" resultMap="roleMap"/>
</resultMap>
<resultMap id="roleMap" type="com.example.domain.Role">
<id property="roleId" column="rid"/>
<result property="roleName" column="ROLE_NAME"/>
<result property="roleDesc" column="ROLE_DESC"/>
</resultMap>
<select id="findAll" resultMap="userMap">
SELECT u.*,r.ID as rid,r.ROLE_DESC,r.ROLE_NAME FROM user u
LEFT OUTER JOIN user_role ur on u.id = ur.UID
LEFT OUTER JOIN role r on ur.RID = r.ID
</select>
</mapper>

  实现多对多关系查询的主要工作都放在了这里,首先通过resultMap 声明用户类的结果映射,id以及result等标签就是User类中的基本属性,User类中的角色属性roles通过collection集合标签来映射到结果集中,<collection property="roles" ofType="com.example.domain.Role" resultMap="roleMap"/>,property对应User类中声明的roles属性,ofType用于标识集合中元素的类型,resultMap用于引用其他的结果映射来说明集合中元素的属性,在这里为roleMap。如果roleMap不在其他地方使用,也可以直接将角色的属性直接配置在collection属性的子集里,如以下形式也可以使用。

    <resultMap id="userMap" type="com.example.domain.User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="birthday" column="birthday"/>
<result property="sex" column="sex"/>
<result property="address" column="address"/>
<!--<collection property="roles" ofType="com.example.domain.Role" resultMap="roleMap"/>-->
<collection property="roles" ofType="com.example.domain.Role">
        <!--这里的rid是role表中的id,在select语句中为了防止id字段在两个表中都出现导致的重复,所以给role的字段id 起了别名 注意要与select中的别名保持一致-->
<id property="roleId" column="rid"/>
<result property="roleName" column="ROLE_NAME"/>
<result property="roleDesc" column="ROLE_DESC"/>
</collection>
</resultMap>

select中的SQL查询语句解释:

 <select id="findAll" resultMap="userMap">
SELECT u.*,r.ID as rid,r.ROLE_DESC,r.ROLE_NAME FROM user u
LEFT OUTER JOIN user_role ur on u.id = ur.UID
LEFT OUTER JOIN role r on ur.RID = r.ID
</select>

  u.*:查询USER表中所有的属性

  r.ID as rid:对于role表中的id起一个别名rid

  user u LEFT OUTER JOIN user_role ur on u.id = ur.UID:前面的表左连接后面的表,并且连接条件是User表中的id与User_role表中的uid相等

  5.测试代码

 public class UserDaoTest {
private InputStream in;
private SqlSession session; private UserDao userDao;
private SqlSessionFactory factory;
@Before
public void init()throws Exception{
//获取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//获取工厂
factory = new SqlSessionFactoryBuilder().build(in); session = factory.openSession(); userDao = session.getMapper(UserDao.class);
}
@After
public void destory()throws Exception{
session.commit();
session.close();
in.close();
}
@Test
public void findAllTest(){
List<User> userList = userDao.findAll();
for (User user: userList){
System.out.println("每个用户的信息");
System.out.println(user);
System.out.println(user.getRoles());
}
}

6.测试结果

mybatis多表查询之多对多关系查询的实现-xml方式的更多相关文章

  1. mybatis实战教程二:多对一关联查询(一对多)

    多对一关联查询 一.数据库关系.article表和user表示多对一的关系 CREATE TABLE `article` ( `id` ) NOT NULL AUTO_INCREMENT, `user ...

  2. Hibernate 、多表关联映射 - 多对多关系映射(many-to-many)

    hibernate.cfg.xml: <hibernate-configuration> <session-factory name="sessionFactory&quo ...

  3. 数据表设计:多对多关系E-R图转换——中间表

    链接:https://blog.csdn.net/vainfanfan/article/details/80568784 链接2:https://www.cnblogs.com/hiwangzi/p/ ...

  4. Hibernate 、多表关联映射-多对一关系(many-to-one)

    Hibernate.cfg.xml: <session-factory name="sessionFactory"> <property name="h ...

  5. mybatis的动态sql编写以及一对一关系查询和一对多的查询

    创建mybatis数据库,运行以下sql语句 /* SQLyog Ultimate v8.32 MySQL - 5.5.27 : Database - mybatis **************** ...

  6. Django-多对多关系的三种创建方式-forms组件使用-cookie与session-08

    目录 表模型类多对多关系的三种创建方式 django forms 组件 登录功能手写推理过程 整段代码可以放过来 forms 组件使用 forms 后端定义规则并校验结果 forms 前端渲染标签组件 ...

  7. [NHibernate]多对多关系(关联查询)

    目录 写在前面 文档与系列文章 多对多关系关联查询 总结 写在前面 上篇文章介绍了nhibernate中对一对多关系进行关联查询的几种方式,以及在使用过程需要注意的问题.这篇文章对多对多关系的查询处理 ...

  8. [转]NHibernate之旅(11):探索多对多关系及其关联查询

    本节内容 多对多关系引入 多对多映射关系 多对多关联查询 1.原生SQL关联查询 2.HQL关联查询 3.Criteria API关联查询 结语 多对多关系引入 让我们再次回顾在第二篇中建立的数据模型 ...

  9. MySQL基础9-主键约束、外键约束、等值连接查询、一对一和多对多关系

    1.主键约束和外键约束 外键约束 * 外键必须是另一表的主键的值(外键要引用主键!) * 外键可以重复 * 外键可以为空 * 一张表中可以有多个外键! 概念模型在数据库中成为表 数据库表中的多对一关系 ...

随机推荐

  1. 洛谷P2472 [SCOI2007]蜥蜴 题解

    题目链接: https://www.luogu.org/problemnew/show/P2472 分析: 这道题用最大流解决. 首先构建模型. 一根柱子可以跳入和跳出,于是拆成两个点:入点和出点. ...

  2. 开源一个好用的nodejs访问mysql类库

    一.背景问题 自nodejs诞生以来出现了一大批的web框架如express koa2 egg等等,前端可以不再依赖后端可以自己控制服务端的逻辑.原来的后端开发同学的阵地前端如今同样也写的风生水起,撸 ...

  3. [leetcode ]429. N-ary Tree Level Order Traversale (easy)

    原题 思路: bfs,每一层遍历一次加到一个vector,同时把该点的子元素加到queue中. class Solution { public: vector<vector<int> ...

  4. RDB和AOF的区别

    redis的持久化方式RDB和AOF的区别   1.前言 最近在项目中使用到Redis做缓存,方便多个业务进程之间共享数据.由于Redis的数据都存放在内存中,如果没有配置持久化,redis重启后数据 ...

  5. VS Code 安装 LeetCode 插件

    练习算法绕不开的一个网站就是力扣,很多小伙伴为了拿到大厂 offer,刷题都刷到吐了. 然而如果直接在 LeetCode 上写代码,那是很痛苦的一件事,那就相当于用 txt 写代码一样,没有 IDE ...

  6. Python字典排序

    利用引出一个例子来理解 例如:比如使用Python字典排序,d={'a':1,'c':3,'b':2}按值升序排列,我们可以用sorted高阶函数或者用列表的.sort()方法.下面具体阐述两种排序方 ...

  7. 【Algorithm】插入排序法

    通常人们整理桥牌的方法是一张一张的来,将每一张插入到其他已经有序的牌中的适当位置. • 思想:每步将一个待排序的记录,按其顺序码大小插入到前面已经排序的序列的合适位置,直到全部插入排序完为止. Jav ...

  8. Eclipse "Adb failed to restart !"

    今天遇到这个问题,如图所示: 上网找了下,原来是电脑上的各种手机助手抢占了手机链接.http://blog.csdn.net/zhufuing/article/details/19398125 说得很 ...

  9. CentOS系统故障 | 一桩"血案"引发的容器存储驱动比较

    写在前面: 由于红帽在Linux界的影响力,相信很多朋友在测试和生产系统用的是RedHat或者CentOS系统,这次我在CentOS系统上遇到了一个很有意思的故障,通过这次故障的原因分析及解决,特意写 ...

  10. 在vue中监听storage的变化

    1.首先在main.js中给Vue.protorype注册一个全局方法,其中,我们约定好了想要监听的sessionStorage的key值为’watchStorage’,然后创建一个StorageEv ...