Mybatis入门:4(多表查询操作)
多表查询操作
Mybatis的多表操作
表之间的关系有几种:一对多、一对一、多对一、多对多
举例:
用户和订单就是一对多——一个用户可以下多个订单
订单和用户就是多对一——多个订单属于同一个用户
人和身份证号就是一对一
一个人只能有一个身份证号
一个身份证号只能属于一个人
老师和学生之间就是多对多
一个学生可以被多个老师教过
一个老师可以教多个学生
特例:
如果拿出每-一个订单,他都只能属于一个用户。
所以Mybatis就把多对一看成了一对一。
我们首先建立了两个新的表格方便操作,如下:
account表格:
user表格:
mybatis中的多表查询:
示例:用户和账户
一个用户可以有多个账户
一个账户只能属于一个用户(多个账户也可以属于同一个用户)
步骤:
- 建立两张表:用户表,账户表
让用户表和账户表之间具备一对多的关系:需要使用外键在账户表中添加
MySQL外键的作用:主要目的是控制存储在外键表中的数据。使两张表形成关联,外键只能引用外表中列的值!
当创建或更改表时可通过定义 FOREIGN KEY 约束来创建外键 - 建立两个实体类:用户实体类和账户实体类
让用户和账户的实体类能体现出啦一-对多的关系 - 建立两个配置文件
用户的配置文件
账户的配置文件 - 实现配置:
当我们查询用户时,可以同时得到用户下所包含的账户信息
当我们查询账户时,可以同时得到账户的所属用户信息
一对一操作
一.通过写Account子类的方式查询(不太常用)
<!--查询所有账户同时包含用户名和地址信息--><select id="findAllAccount" resultType="accountuser">select a.*,u.username,u.address from account a , user uwhere u.id = a.uid;</select>
Account类
package com.domain;import java.io.Serializable;public class Account implements Serializable {private Integer id;private Integer uid; //外键private Double money;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public Integer getUid() {return uid;}public void setUid(Integer uid) {this.uid = uid;}public Double getMoney() {return money;}public void setMoney(Double money) {this.money = money;}@Overridepublic String toString() {return "Account{" +"id=" + id +", uid=" + uid +", money=" + money +'}';}
}
AccountUser类(Account子类)
package com.domain;public class AccountUser extends Account { //继承了Account类private String username;private String address;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}@Overridepublic String toString() {return super.toString()+" AccountUser{" + //super.toString()调用父类的toString()方法"username='" + username + '\'' +", address='" + address + '\'' +'}';}
}
User类
package com.domain;import java.io.Serializable;
import java.util.Date;
import java.util.List;public class User implements Serializable {private Integer id;private String username;private String address;private String sex;private Date birthday;//一对多关系映射:主表实体应该包含从表实体的集合引用private List<Account> accounts;public List<Account> getAccounts() {return accounts;}public void setAccounts(List<Account> accounts) {this.accounts = accounts;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", address='" + address + '\'' +", sex='" + sex + '\'' +", birthday=" + birthday +'}';}
}
测试类
/*** 测试查询所有账户,同时包含用户名称和地址*/@Testpublic void testFindAllAccountUser(){List<AccountUser> aus = accountDao.findAllAccount();for(AccountUser au : aus){System.out.println(au);}}
结果:
大概思路
1.测试类findAllAccount()方法返回AccountUser集合,输出集合
2.执行findAllAccount()方法,转入xml配置文件,执行sql语句查询
3.返回AccountUser类型的查询结果,执行子类的toString方法
4.super.toString()执行父类的toString方法
二.通过建立实体类关系的方式(常用)
<!-- 定义封装account和user的resultMap --><!-- 一对一的关系映射:配置封装user的内容--><resultMap id="accountUserMap" type="account"><id property="id" column="aid"/> <!--此处的aid为表中id的别名--><result property="uid" column="uid"/><result property="money" column="money"/><association property="user" javaType="user"> <!--由于使用了别名,所以直接写user就行了--><!--为了防止我们开发出错,在没有特别要求的情况下,column名可以完全和property名称一致,否则当我们没有对应上的时候,数据库匹配不到--><id property="id" column="id"/><result column="username" property="username"/><result column="address" property="address"/><result column="sex" property="sex"/><result column="birthday" property="birthday"/></association></resultMap><!-- 查询所有 --><select id="findAll" resultMap="accountUserMap"><!-- as可理解为:用作、当成,作用;一般是重命名列名或者表名。(主要为了查询方便)-->select u.*,a.id as aid,a.uid,a.money from account a,user u where u.id = a.uid;</select>
association标签的作用:就是将另一张表的字段关联过来 然后一起映射到实体类。
Account类(在之前的基础上改造)
package com.domain;import java.io.Serializable;public class Account implements Serializable {private Integer id;private Integer uid; //外键private Double money;//从表实体应该包含一个主表实体的对象引用private User user;public User getUser() {return user;}public void setUser(User user) {this.user = user;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public Integer getUid() {return uid;}public void setUid(Integer uid) {this.uid = uid;}public Double getMoney() {return money;}public void setMoney(Double money) {this.money = money;}@Overridepublic String toString() {return "Account{" +"id=" + id +", uid=" + uid +", money=" + money +'}';}
}
User类(跟上面一样,不变)
测试类
@Testpublic void testFindAll(){List<Account> accounts = accountDao.findAll();for(Account account : accounts){System.out.println("--------每个account的信息------------");System.out.println(account);System.out.println(account.getUser());//其实可以直接在Account类那里将toString()方法重写一遍,加上user,就不用调用getUser()方法了}}
结果:
一对多操作
一个用户存在多个账户的情况
<!-- 定义User的resultMap--><!--一对多查询--><resultMap id="userAccountMap" type="user"><id property="id" column="id"/><result property="username" column="username"/><result property="address" column="address"/><result property="sex" column="sex"/><result property="birthday" column="birthday"/><!-- 配置user对象中accounts集合的映射 --><collection property="accounts" ofType="account"> <!--ofType指的是集合accounts的类型--><id column="aid" property="id"/> <!--aid为列别名,起别名是因为主子表都有该字段--><result column="uid" property="uid"/><result column="money" property="money"/></collection></resultMap><!-- 查询所有 --><select id="findAll" resultMap="userAccountMap"><!-- left join(左联接)返回包括左表(user)中的所有记录和右表(account)中联结字段相等(即u.id = a.uid)的记录,即返回user表和满足u.id = a.uid条件的account表 -->select * from user u left outer join account a on u.id = a.uid</select>
注:
- left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录
- right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录
- inner join(等值连接) 只返回两个表中联结字段相等的行
- outer join(外连接) 可分为左外连接left outer join和右外连接right outer join
上面的left join(左联结)表示返回所有user表和满足u.id = a.uid条件的account表内容
User类(添加上了Account集合属性)
package com.domain;import java.io.Serializable;
import java.util.Date;
import java.util.List;public class User implements Serializable {private Integer id;private String username;private String address;private String sex;private Date birthday;//一对多关系映射:主表实体应该包含从表实体的集合引用private List<Account> accounts;public List<Account> getAccounts() {return accounts;}public void setAccounts(List<Account> accounts) {this.accounts = accounts;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", address='" + address + '\'' +", sex='" + sex + '\'' +", birthday=" + birthday +'}';}
}
测试类
@Testpublic void testFindAll(){List<User> users = userDao.findAll();for(User user : users){System.out.println("-----每个用户的信息------");System.out.println(user);System.out.println(user.getAccounts());}}
结果:
多对多操作
示例:用户和角色
一个用户可以有多个角色
一个角色可以赋予多个用户
步骤:
- 建立两张表:用户表,角色表
让用户表和角色表具有多对多的关系。需要使用中间表,中间表中包含各自的主键,在中间表中是外键。 - 建立两个实体类:用户实体类和角色实体类
让用户和角色的实体类能体现出来多对多的关系
各自包含对方一个集合引用 - 建立两个配置文件
用户的配置文件
角色的配置文件 - 实现配置:
当我们查询用户时,可以同时得到用户所包含的角色信息
当我们查询角色时,可以同时得到角色的所赋予的用户信息
1.查询角色获取角色下所包含的用户信息
<!--定义role表的resultMap--><resultMap id="roleMap" type="role"><id property="roleId" column="rid"/><result property="roleName" column="role_name"/><result property="roleDesc" column="role_desc"/><collection property="users" ofType="user"><id column="id" property="id"/><result column="username" property="username"/><result column="address" property="address"/><result column="sex" property="sex"/><result column="birthday" property="birthday"/></collection></resultMap><!--查询所有--><select id="findAll" resultMap="roleMap">select u.*,r.id as rid,r.role_name,role_desc from role rleft outer join user_role ur on r.id=ur.ridleft outer join user u on u.id=ur.uid</select>
多对多查询的精华基本都在sql语句的书写上面了…
Role类
package com.domain;import java.io.Serializable;
import java.util.List;public class Role implements Serializable {private Integer roleId;private String roleName;private String roleDesc;private List<User> users;public List<User> getUsers() {return users;}public void setUsers(List<User> users) {this.users = users;}public Integer getRoleId() {return roleId;}public void setRoleId(Integer roleId) {this.roleId = roleId;}public String getRoleName() {return roleName;}public void setRoleName(String roleName) {this.roleName = roleName;}public String getRoleDesc() {return roleDesc;}public void setRoleDesc(String roleDesc) {this.roleDesc = roleDesc;}@Overridepublic String toString() {return "Role{" +"roleId=" + roleId +", roleName='" + roleName + '\'' +", roleDesc='" + roleDesc + '\'' +'}';}
}
User类
package com.domain;import java.io.Serializable;
import java.util.Date;public class User implements Serializable {private Integer id;private String username;private String address;private String sex;private Date birthday;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", address='" + address + '\'' +", sex='" + sex + '\'' +", birthday=" + birthday +'}';}
}
测试类
@Testpublic void testFindAll(){List<Role> roles = roleDao.findAll();for(Role role : roles){System.out.println("-----每个角色的信息------");System.out.println(role);System.out.println(role.getUsers());}}
结果:
2.查询用户获取用户所包含的角色信息
<!--多对多查询--><resultMap id="userMap" type="user"><id property="id" column="id"/><result property="username" column="username"/><result property="address" column="address"/><result property="sex" column="sex"/><result property="birthday" column="birthday"/><!--配置角色集合的映射--><collection property="roles" ofType="role"><id property="roleId" column="rid"/><result property="roleName" column="role_name"/><result property="roleDesc" column="role_desc"/></collection></resultMap><!-- 查询所有 --><select id="findAll" resultMap="userMap">select u.*,r.id as rid,r.role_name,role_desc from user uleft outer join user_role ur on u.id=ur.uidleft outer join role r on r.id=ur.rid</select>
通过观察我们可以发现UserDao的配置文件中的sql查询语句刚好是和上面查询角色时的反过来的。
Role类不变
User类(加上Role类型的集合属性)
package com.domain;import java.io.Serializable;
import java.util.Date;
import java.util.List;public class User implements Serializable {private Integer id;private String username;private String address;private String sex;private Date birthday;//多对多的关系映射:一个用户可以具备多个角色private List<Role>roles;public List<Role> getRoles() {return roles;}public void setRoles(List<Role> roles) {this.roles = roles;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", address='" + address + '\'' +", sex='" + sex + '\'' +", birthday=" + birthday +'}';}
}
测试类
@Testpublic void testFindAll(){List<User> users = userDao.findAll();for(User user : users){System.out.println("-----每个用户的信息------");System.out.println(user);System.out.println(user.getRoles());}}
相关文章:

Python for虚幻引擎编辑器工具脚本学习教程
Python for Unreal Engine Editor Tools Scripting MP4 |视频:h264,1280720 |音频:AAC,44.1 KHz,2 Ch 语言:英语中英文字幕(根据原英文字幕机译更准确) |时长:23节课(4h 8m) |大小解压后:2.7 GB 含课程文件…

C++ Windows进程管理
功能: 1.各个进程启动、挂起、恢复、停止等 2.监听进程的运行状态,进程退出(正常、非正常)时,通知用户 3.异步队列 4.线程安全 进程管理器类: #ifndef __ProcessManager_ProcessManager_H__ #define __Proc…

shell中和||的使用方法
&&运算符:command1 && command2&&左边的命令(命令1)返回真(即返回0,成功被执行)后,&&右边的命令(命令2)才能够被执行;换句话说,“如果…

SQL中内连接、外连接、交叉连接
SQL中内连接、外连接、交叉连接 SQL连接可以分为内连接、外连接、交叉连接。 数据库数据: book表 stu表 1.内连接 1.1.等值连接:在连接条件中使用等于号()运算符比较被连接列的列值,其查询结果中列…

Blender从头开始装配和动画制作低多边形风格的FPS手臂
Rigging and Animating Low Poly FPS Arms in Blender MP4 |视频:h264,1280720 |音频:AAC,44.1 KHz,2 Ch 语言:英语中英文字幕(根据原英文字幕机译更准确) |时长:21节课(4h 56m) |大小解压后:3.16 GB 含课程…

Mybatis复习笔记3:映射文件详解
映射文件详解 参数处理(#和$的区别) #{}:可以获取map中的值或者实体对象属性的值;${}:可以获取map中的值或者实体对象属性的值; select * from person where id${id} and name#{name} # 控制台输出&…
TMS320F28335项目开发记录2_CCS与JTAG仿真器连接问题汇总
CCS与仿真器连接问题 实际使用过程中。仿真器和CCS连接可能出现这样或那样的问题,或许你的连接非常成功,没碰到过什么问题。但我的问题的确不少,可能与电脑配置有关吧,也可能与人品有关吧。 以下的自己的一些错误和解决方法总…

Mysql备份与还原及优化方法
Mysql备份一般采用mysqldump命令,命令形式一般如下:$ mysqldump –hhostname –uuser –ppassword–Pport db_name > db_name.sql默认情况下,不备份存储过程和函数,若要备份存储过程和函数,要加上-R选项,…

HashTable和HashMap的区别详解
HashTable和HashMap的区别详解 一、HashMap简介 HashMap是基于哈希表实现的,每一个元素是一个key-value对,其内部通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长。 HashMap是非线程安全的&…

Unity电子游戏优化终极指南 The Ultimate Guide to Video Game Optimisation
大小解压后:5.2G 含课程文件 时长9h 1280X720 MP4 语言:英语中英文字幕(根据原英文字幕机译更准确) 电子游戏优化终极指南 信息: 学会从你的Unity游戏开发项目中挤出每一帧表现 你会学到什么 –如何为游戏制定绩效预算并坚持下…

Mybatis复习笔记:4
关于Mybatis中的一些注意点 一.关于实体类属性 当我们封装的时候我们一般要求实体类中和数据库的列名保持一致。 如果不一致将会导致查询结果为空。 解决属性名和数据库中表的字段名不一致的方法 1.在sql语句中给数据库中的字段起别名 如: <select id"…

USB_HID C#测试例程
USB_HID C#测试例程 报告模式(按键、LED、ADC) 一、简介 Usb无处不在,而hid则免驱,使用更加方便,本方案主要是基于STM32F10X系列单片机的usb hid开发,计算机软件采用VS2013 C#开发。 二、接线图示意 三、开…

基于Linux的视频传输系统(上大学时參加的一个大赛的论文)
文件夹<?xml:namespace prefix o ns "urn:schemas-microsoft-com:office:office" />1原创性声明----------------------------------------------------32 摘要----------------------------------------------------------43系统方案---------------------…

UE5真实环境设计入门学习教程
大小解压后:4.69G 时长4h 30m 1280X720 MP4 语言:英语中英文字幕(根据原英文字幕机译更准确) 虚幻引擎5–面向初学者的真实环境设计 Unreal Engine 5 – Realistic Environment Design for Beginners 信息: 通过一步一步创建一个…

Spring复习笔记:1
ApplicationContext的三个常用实现类: ClassPathXmLApplicationContext: 它可以加载类路径下的配置文件,要求配置文件必须在类路径下。不在类路径的话,加载不了。FileSystemXmLApplicationContext: 它可以加载磁盘任意路径下的配置文件(必须有访问权限&…

Android 趣味应用—— 短信编辑器
修改短信数据库,从而生成任意手机号发送的短信。 AndroidManifest.xml <?xml version"1.0" encoding"utf-8"?> <manifest xmlns:android"http://schemas.android.com/apk/res/android"package"com.example.dudon.fak…
Uber体验之路
第一次听说uber,是2014年初的时候,那时候互联网热门新闻,经常冒出这家公司。 第一次体验uber,是2014.10.3,去机场接人,叫了专车。 第一次觉得uber体验好,是2014年感恩节的时候,它在深…

容器和虚拟机的对比
容器和虚拟机的对比 “敏捷”和“高性能”是容器相较于虚拟机最大的优势,也是它能够在 PaaS 这种更细粒度的资源管理平台上大行其道的重要原因。 不过,有利就有弊,基于 Linux Namespace 的隔离机制相比于虚拟化技术也有很多不足之处ÿ…

Spring复习笔记:2
Spring中的依赖注入 IOC的作用: 降低程序间的耦合(依赖关系) 依赖关系的管理: 以后都交给spring来维护,在当前类需要用到其他类的对象,由spring为我们提供,我们只需要在配置文件中说明依赖关系的维护,就称之为依赖注入…

Unity Android 2021:用C#打造3D ZigZag赛车游戏
Unity Android 2021 : Build 3D ZigZag Racing Game with C# MP4 |视频:h264,1280720 |音频:AAC,44.1 KHz,2 Ch 语言:英语中英文字幕(根据原英文字幕机译更准确) |时长:65节课(11h 7m) |大小解压后:3.6 GB …

封装了一套WeCenter的IOS SDK
度过了忙碌且迷茫的2015年,迎来了的郁闷且彷徨的2016年。 与哥们商量做些什么,谈不上创业也不是项目,只是想让2016年不必如2015年一样迷茫,也慰藉一下2016年的彷徨。 方向么,考察了几个行业,也做了些调研&a…

java多线程样例
这里我们做一个完整的样例来说明线程产生的方式不同而生成的线程的差别: package debug;import java.io.*;import java.lang.Thread;class MyThread extends Thread{ public int x 0; public void run(){ System.out.println(x); }}class R implements Runn…

Spring复习笔记:3
Spring基于xml的案例实践 在数据库中创建一张新的表 create table account(id int primary key auto_increment,name varchar(40),money float )character set utf8 collate utf8_general_ci;往表中导入数据 insert into account(name,money) values(aaa,1000); insert into…

Blender多米诺骨牌动画学习教程 The Impossible Domino Run in Blender
流派:电子学习| MP4 |视频:h264,1280720 |音频:AAC,48.0 KHz 语言:英语中英文字幕(根据原英文字幕机译更准确)|大小:8.53 GB 含课程文件 |时长:8h 20m Blender的运动跟踪,建模,渲染和合成工具集…

unity3d游戏开发猜想——当程序猿老去
程序猿将代码注入生命去打造互联网的浪潮之巅。当有一天他们老了。会走向那里,会做些什么?非常多年以后,在我60岁的那天早晨,天刚蒙蒙亮我就起床了,先去公园晨练,然后回来做早餐(50岁的时候我学…

【JavaScript】JavaScript基础-变量、运算符与控制语句
一.变量 变量: 定义一个变量,系统会为之分配一块内存,程序可以用变量名来表示这块内存中的数据。 由于javascript采用的是弱类型的变量形式,因此,在声明一个变量的时候,我们不必声明它的类型,但…

ROW_NUMBER() OVER()函数用法详解 (分组排序 例子多)
ROW_NUMBER() OVER()函数用法详解 (分组排序 例子多) https://blog.csdn.net/qq_25221835/article/details/82762416 posted on 2019-09-05 01:00 竹径风声 阅读(...) 评论(...) 编辑 收藏 转载于:https://www.cnblogs.com/girl1314/p/11462711.html

Blender+Substance Painter全流程制作真实的机器人学习教程
MP4 |视频:h264,1280720 |音频:AAC,44.1 KHz,2 Ch 语言:英语中英文字幕(根据原英文字幕机译更准确) |时长:44节课(10h 52m) |大小解压后:9.9 GB 含课程素材 如何使用Blender 2.8和Substance Painter制作真…

Spring复习笔记:4
在复习笔记三中我们进行的案例的编写,我们可以发现,就算使用了注解的方式,xml配置文件文件还是不能够删除,现在我们来将一些新的注解可以让我们去掉xml配置文件。 Configuration 作用:指定当前类是一个配置类 细节&a…

Extjs PROXY查询params无法传参,改用extraParams
转载于:https://www.cnblogs.com/cocoat/p/5153009.html