MyBatis 多表操作

文章源码

一对一查询

需求:查询所有账户信息,关联查询下单用户信息。

注意:因为一个账户信息只能供某个用户使用,所以从查询账户信息出发关联查询用户信息为一对一查询。如果从用户信息出发关联查询用户下的账户信息则为一对多查询,因为一个用户可以有多个账户。

可以使用 resultMap,定义专门的 resultMap 用于映射一对一查询结果。

  • 定义账户信息的数据表

    1. DROP TABLE IF EXISTS `account`;
    2. CREATE TABLE `account` (
    3. `ID` int(11) NOT NULL COMMENT '编号',
    4. `UID` int(11) default NULL COMMENT '用户编号',
    5. `MONEY` double default NULL COMMENT '金额',
    6. PRIMARY KEY (`ID`),
    7. KEY `FK_Reference_8` (`UID`),
    8. CONSTRAINT `FK_Reference_8` FOREIGN KEY (`UID`) REFERENCES `user` (`id`)
    9. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    10. insert into `account`(`ID`,`UID`,`MONEY`) values (1,41,1000),(2,45,1000),(3,41,2000);
  • 定义账户信息的实体类

    1. package cn.parzulpan.domain;
    2. import java.io.Serializable;
    3. /**
    4. * @Author : parzulpan
    5. * @Time : 2020-12
    6. * @Desc :
    7. */
    8. public class Account implements Serializable {
    9. private Integer id;
    10. private Integer uid;
    11. private Double money;
    12. private User user;
    13. public Integer getId() {
    14. return id;
    15. }
    16. public void setId(Integer id) {
    17. this.id = id;
    18. }
    19. public Integer getUid() {
    20. return uid;
    21. }
    22. public void setUid(Integer uid) {
    23. this.uid = uid;
    24. }
    25. public Double getMoney() {
    26. return money;
    27. }
    28. public void setMoney(Double money) {
    29. this.money = money;
    30. }
    31. public User getUser() {
    32. return user;
    33. }
    34. public void setUser(User user) {
    35. this.user = user;
    36. }
    37. @Override
    38. public String toString() {
    39. return "Account{" +
    40. "id=" + id +
    41. ", uid=" + uid +
    42. ", money=" + money +
    43. ", user=" + user +
    44. '}';
    45. }
    46. }
  • 编写 SQL

    1. select u.*, a.id as aid, a.uid, a.money
    2. from account a, user u
    3. where a.uid = u.id;
  • 定义账户的持久层 DAO 接口

    1. package cn.parzulpan.dao;
    2. import cn.parzulpan.domain.Account;
    3. import java.util.List;
    4. /**
    5. * @Author : parzulpan
    6. * @Time : 2020-12
    7. * @Desc :
    8. */
    9. public interface AccountDAO {
    10. /**
    11. * 查询所有账户,同时获取账户的所属用户名称以及它的地址信息
    12. * @return
    13. */
    14. List<Account> findAll();
    15. }
  • 配置 AccountDAO.xml 文件

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <!DOCTYPE mapper
    3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    5. <mapper namespace="cn.parzulpan.dao.AccountDAO">
    6. <!-- 建立对应关系 -->
    7. <resultMap id="accountMap" type="account">
    8. <id column="aid" property="id"/>
    9. <result column="uid" property="uid"/>
    10. <result column="money" property="money"/>
    11. <!-- 用于指定从数据表方的引用实体属性 -->
    12. <association property="user" javaType="user">
    13. <id column="id" property="id"/>
    14. <result column="username" property="username"/>
    15. <result column="sex" property="sex"/>
    16. <result column="birthday" property="birthday"/>
    17. <result column="address" property="address"/>
    18. </association>
    19. </resultMap>
    20. <select id="findAll" resultMap="accountMap">
    21. select u.*, a.id as aid, a.uid, a.money
    22. from account a, user u
    23. where a.uid = u.id;
    24. </select>
    25. </mapper>
  • 测试

    1. package cn.parzulpan.test;
    2. import cn.parzulpan.dao.AccountDAO;
    3. import cn.parzulpan.domain.Account;
    4. import org.apache.ibatis.io.Resources;
    5. import org.apache.ibatis.session.SqlSession;
    6. import org.apache.ibatis.session.SqlSessionFactory;
    7. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    8. import org.junit.After;
    9. import org.junit.Before;
    10. import org.junit.Test;
    11. import java.io.IOException;
    12. import java.io.InputStream;
    13. import java.util.List;
    14. /**
    15. * @Author : parzulpan
    16. * @Time : 2020-12
    17. * @Desc : 多表查询
    18. */
    19. public class MyBatisQueryTest {
    20. private InputStream is;
    21. SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    22. private SqlSessionFactory factory;
    23. private SqlSession session;
    24. private AccountDAO accountDAO;
    25. @Before
    26. public void init() throws IOException {
    27. is = Resources.getResourceAsStream("SqlMapConfig.xml");
    28. factory = builder.build(is);
    29. session = factory.openSession();
    30. accountDAO = session.getMapper(AccountDAO.class);
    31. }
    32. @After
    33. public void destroy() throws IOException {
    34. session.commit(); // 事务提交
    35. session.close();
    36. is.close();
    37. }
    38. @Test
    39. public void findAllTest() {
    40. List<Account> accounts = accountDAO.findAll();
    41. for (Account account : accounts) {
    42. System.out.println(account);
    43. System.out.println(account.getUser());
    44. }
    45. }
    46. }

一对多查询

需求:查询所有用户信息及用户关联的账户信息。

分析:用户信息和他的账户信息为一对多关系,并且查询过程中如果用户没有账户信息,此时也要将用户信息查询出来,所以左外连接查询比较合适。

  • 编写 SQL

    1. select u.*, a.id as id, a.uid, a.money
    2. from user u left join account a on u.id = a. uid;
  • User 类加入 List<Account>

  • 用户持久层 DAO 接口中加入查询方法

    1. /**
    2. * 查询所有用户,同时获取出每个用户下的所有账户信息
    3. * @return
    4. */
    5. List<User> findAllAndAccount();
  • 配置 UserDAO.xml 文件

    1. <resultMap id="userMap" type="user">
    2. <id column="id" property="id"/>
    3. <result column="username" property="username"/>
    4. <result column="address" property="address"/>
    5. <result column="sex" property="sex"/>
    6. <result column="birthday" property="birthday"/>
    7. <!-- collection 是用于建立一对多中集合属性的对应关系 ofType 用于指定集合元素的数据类型 -->
    8. <collection property="accounts" ofType="account">
    9. <id column="aid" property="id"/>
    10. <result column="uid" property="uid"/>
    11. <result column="money" property="money"/>
    12. </collection>
    13. </resultMap>
    14. <select id="findAllAndAccount" resultMap="userMap">
    15. select u.*, a.id as aid, a.uid, a.money
    16. from user u left join account a on u.id = a. uid;
    17. </select>
  • 测试

    1. @Test
    2. public void findAllAndAccountTest() {
    3. List<User> users = userDAO.findAllAndAccount();
    4. for (User user : users) {
    5. System.out.println();
    6. System.out.println("----- " + user.getUsername() + " -----");
    7. System.out.println(user);
    8. System.out.println(user.getAccounts());
    9. }
    10. }

多对多查询

需求:实现查询所有对象并且加载它所分配的用户信息。

注意:查询角色我们需要用到Role表,但角色分配的用户的信息我们并不能直接找到用户信息,而是要通过中间表(USER_ROLE 表)才能关联到用户信息。

  • 定义相关的数据表

    1. # -----
    2. DROP TABLE IF EXISTS `role`;
    3. CREATE TABLE `role` (
    4. `ID` int(11) NOT NULL COMMENT '编号',
    5. `ROLE_NAME` varchar(30) default NULL COMMENT '角色名称',
    6. `ROLE_DESC` varchar(60) default NULL COMMENT '角色描述',
    7. PRIMARY KEY (`ID`)
    8. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    9. insert into `role`(`ID`,`ROLE_NAME`,`ROLE_DESC`) values (1,'院长','管理整个学院'),(2,'总裁','管理整个公司'),(3,'校长','管理整个学校');
    10. # -----
    11. DROP TABLE IF EXISTS `user_role`;
    12. CREATE TABLE `user_role` (
    13. `UID` int(11) NOT NULL COMMENT '用户编号',
    14. `RID` int(11) NOT NULL COMMENT '角色编号',
    15. PRIMARY KEY (`UID`,`RID`),
    16. KEY `FK_Reference_10` (`RID`),
    17. CONSTRAINT `FK_Reference_10` FOREIGN KEY (`RID`) REFERENCES `role` (`ID`),
    18. CONSTRAINT `FK_Reference_9` FOREIGN KEY (`UID`) REFERENCES `user` (`id`)
    19. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    20. insert into `user_role`(`UID`,`RID`) values (41,1),(45,1),(41,2);
  • 定义角色信息的实体类

    1. package cn.parzulpan.domain;
    2. import java.io.Serializable;
    3. import java.util.List;
    4. /**
    5. * @Author : parzulpan
    6. * @Time : 2020-12
    7. * @Desc : 角色实体类
    8. */
    9. public class Role implements Serializable {
    10. private Integer roleId;
    11. private String roleName;
    12. private String roleDesc;
    13. private List<User> users; //多对多的关系映射:一个角色可以赋予多个用户
    14. public Integer getRoleId() {
    15. return roleId;
    16. }
    17. public void setRoleId(Integer roleId) {
    18. this.roleId = roleId;
    19. }
    20. public String getRoleName() {
    21. return roleName;
    22. }
    23. public void setRoleName(String roleName) {
    24. this.roleName = roleName;
    25. }
    26. public String getRoleDesc() {
    27. return roleDesc;
    28. }
    29. public void setRoleDesc(String roleDesc) {
    30. this.roleDesc = roleDesc;
    31. }
    32. public List<User> getUsers() {
    33. return users;
    34. }
    35. public void setUsers(List<User> users) {
    36. this.users = users;
    37. }
    38. @Override
    39. public String toString() {
    40. return "Role{" +
    41. "roleId=" + roleId +
    42. ", roleName='" + roleName + '\'' +
    43. ", roleDesc='" + roleDesc + '\'' +
    44. ", users=" + users +
    45. '}';
    46. }
    47. }
  • 编写 RoleDAO 持久层接口

    1. package cn.parzulpan.dao;
    2. import cn.parzulpan.domain.Role;
    3. import java.util.List;
    4. /**
    5. * @Author : parzulpan
    6. * @Time : 2020-12
    7. * @Desc :
    8. */
    9. public interface RoleDAO {
    10. /**
    11. * 查询所有角色
    12. * @return
    13. */
    14. List<Role> findAll();
    15. }
  • 编写映射文件

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <!DOCTYPE mapper
    3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    5. <mapper namespace="cn.parzulpan.dao.RoleDAO">
    6. <!-- 建立对应关系 -->
    7. <resultMap id="roleMap" type="role">
    8. <id property="roleId" column="rid"/>
    9. <result property="roleName" column="role_name"/>
    10. <result property="roleDesc" column="role_desc"/>
    11. <collection property="users" ofType="user">
    12. <id column="id" property="id"/>
    13. <result column="username" property="username"/>
    14. <result column="address" property="address"/>
    15. <result column="sex" property="sex"/>
    16. <result column="birthday" property="birthday"/>
    17. </collection>
    18. </resultMap>
    19. <select id="findAll" resultMap="roleMap">
    20. select r.id as rid, r.role_name, r.role_desc, u.*
    21. from role r left outer join user_role ur on r.id = ur.rid left outer join user u on u.id = ur.uid
    22. </select>
    23. </mapper>
  • 测试

    1. package cn.parzulpan.test;
    2. import cn.parzulpan.dao.AccountDAO;
    3. import cn.parzulpan.dao.RoleDAO;
    4. import cn.parzulpan.domain.Account;
    5. import cn.parzulpan.domain.Role;
    6. import cn.parzulpan.domain.User;
    7. import org.apache.ibatis.io.Resources;
    8. import org.apache.ibatis.session.SqlSession;
    9. import org.apache.ibatis.session.SqlSessionFactory;
    10. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    11. import org.junit.After;
    12. import org.junit.Before;
    13. import org.junit.Test;
    14. import java.io.IOException;
    15. import java.io.InputStream;
    16. import java.util.List;
    17. /**
    18. * @Author : parzulpan
    19. * @Time : 2020-12
    20. * @Desc : 多表查询
    21. */
    22. public class MyBatisManyQueryTest {
    23. private InputStream is;
    24. SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    25. private SqlSessionFactory factory;
    26. private SqlSession session;
    27. private RoleDAO roleDAO;
    28. @Before
    29. public void init() throws IOException {
    30. is = Resources.getResourceAsStream("SqlMapConfig.xml");
    31. factory = builder.build(is);
    32. session = factory.openSession();
    33. roleDAO = session.getMapper(RoleDAO.class);
    34. }
    35. @After
    36. public void destroy() throws IOException {
    37. session.commit(); // 事务提交
    38. session.close();
    39. is.close();
    40. }
    41. @Test
    42. public void findAllTest() {
    43. List<Role> roles = roleDAO.findAll();
    44. for (Role role : roles) {
    45. System.out.println();
    46. System.out.println("----- " + " -----");
    47. System.out.println(role);
    48. if (role != null) {
    49. System.out.println(role.getUsers());
    50. }
    51. }
    52. }
    53. }

练习和总结

【MyBatis】MyBatis 多表操作的更多相关文章

  1. Mybatis的多表操作

    1.Mybatis多表查询 1.1 一对一查询 1.1.1 一对一查询的模型MapperScannerConfigurer 用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户 一对一 ...

  2. 阶段3 1.Mybatis_09.Mybatis的多表操作_2 完成account表的建立及实现单表查询

    mybatis中的多表查询:         示例:用户和账户             一个用户可以有多个账户             一个账户只能属于一个用户(多个账户也可以属于同一个用户)    ...

  3. 阶段3 1.Mybatis_09.Mybatis的多表操作_1 mybatis表之间关系分析

    4.mybatis中的多表查询     表之间的关系有几种:         一对多         多对一         一对一         多对多     举例:         用户和订单 ...

  4. 阶段3 1.Mybatis_09.Mybatis的多表操作_8 mybatis多对多操作-查询角色获取角色下所属用户信息

    一个角色对应多个用户 生成getter和setter 查看两个表的数据 中间表定义了谁有角色,谁没有角色 根据中间表的关系,最终查询出来的列表的数据样子.这需要两个左外链接才能实现功能. 第一个左外链 ...

  5. 阶段3 1.Mybatis_09.Mybatis的多表操作_7 mybatis多对多准备角色表的实体类和映射配置

    创建Role表和user_role表 DROP TABLE IF EXISTS `role`; CREATE TABLE `role` ( `ID` int(11) NOT NULL COMMENT ...

  6. 阶段3 1.Mybatis_09.Mybatis的多表操作_6 分析mybatis多对多的步骤并搭建环境

    示例:用户和角色             一个用户可以有多个角色             一个角色可以赋予多个用户         步骤:             1.建立两张表:用户表,角色表    ...

  7. 阶段3 1.Mybatis_09.Mybatis的多表操作_3 完成account的一对一操作-通过写account的子类方式查询

    先把多表查询的sql语句写出来 想要显示的字段 创建一个AccountUser类 继承Account.这样它就会从父类上继承一些信息 这里只需要定义username和address就可以了 .然后生成 ...

  8. 阶段3 1.Mybatis_09.Mybatis的多表操作_9 mybatis多对多操作-查询用户获取用户所包含的角色信息

    sql语句以user作为主表 用户的全部信息,以为用户下的角色的.并不是所有的用户都有角色,有角色的就带角色.没角色的就为null 首先修改实体类 定义List<Role> 生成gette ...

  9. 阶段3 1.Mybatis_09.Mybatis的多表操作_5 完成user的一对多查询操作

    定义List<Account> accounts,生成getter和setter 复制AccountTest类改名UserTest类 修改测试类 还没封装所以Account的list都是n ...

  10. 阶段3 1.Mybatis_09.Mybatis的多表操作_4 完成account一对一操作-建立实体类关系的方式

    定义user的实体.然后生成getter和setter 定义一个可以封装Account和User的Map type这里虽然是account类型 这一段只能保证account的数据完成.并不能保证use ...

随机推荐

  1. ip 子网掩码、网络地址、广播地址计算

    例:已知ip  16.158.165.91/22子网掩码 根据22 得知子网掩码占22位 即:11111111.11111111.11111100.00000000   == 255.255.252. ...

  2. redis学习之——主从复制(replication)

    准备:拥有linux环境,并安装redis mater:主机,进行写操作 slave:从机,进行读操作 一.配置 继续前边的学习.我们是拷贝redis.conf,文件到了/root /redis 下. ...

  3. Array的简单使用(Boost和STL通用)

    目录 目录 介绍 使用 Boost和STL的区别 介绍 本来这一次是想简单介绍一下Boost里面的协程库的使用的,但是Boost.Coroutine已经被废弃了,而Boost.Coroutine2目前 ...

  4. python魔术方法总结

    获取属性 __ getattr __(self, name) 定义当用户试图获取一个不存在的属性时的行为 __ getattribute __(self, name) 定义当该类的属性被访问时的行为 ...

  5. 横向无文件移动--SCshell使用

    1.简介 SCShell是无文件横向移动工具,它依赖ChangeServiceConfigA来运行命令.该工具的优点在于它不会针对SMB执行身份验证.一切都通过DCERPC执行.无需创建服务,而只需通 ...

  6. schema与数据类型优化-高性能mysql

    总结作为开发人员重点注意的内容!这是一篇有关高性能MYSQL第四章schema相关的笔记. 0.前言 在项目中,数据库表列有两个text字段,用来存储大文本,在数据规模达到40万后,如果查询没命中索引 ...

  7. gitbook 安装和使用

    gitbook 安装和使用 安装nodejs  wget https://nodejs.org/dist/v10.22.0/node-v10.22.0-linux-arm64.tar.xz tar - ...

  8. [日常摸鱼][POI2000]病毒-Tire图(AC自动机)+dfs

    https://www.luogu.org/problemnew/show/P2444 (没有bzoj权限号T_T) 字符串题对我这种傻逼来说真是太难了x 题意:输入$n$个01组成的模式串串,判断是 ...

  9. 第一天——编程语言与python

    ------------恢复内容开始------------ what's the python? python是一门编程语言,编程语言就是人用来和计算机沟通的语言,语言就是人与人,人与事物进行沟通的 ...

  10. tkinter + 爬虫 实现影视在线资源系统

    应吾爱朋友现公布代码如下: import tkinter as tk import requests,re,sys,asyncio from tkinter import scrolledtext,E ...