06- 多表查询

9.1 项目环境

9.1.1 项目目录

9.2 关联关系分类

三种:1对1,1对多,多对多

9.2.1 一对一关联关系

人和身份证的关系。一个人只能有一张身份证,一张身份证只能属于一个人。双向【一对一】关联关系。

9.2.2 一对多关联关系

举一个例子:用户和订单的关系。

一个用户可以有多个订单,从用户到订单是【一对多】关联关系。

一个订单只能属于一个人,从订单到人是【一对一】的关联关系。

9.2.3 多对多关联关系

举一个例子:业务系统中,用户和角色的关系。

一个用户可以有多种角色:小明有可能是:经理,员工,总经理

一种角色可以有多个用户:经理这个角色,有多个人:kobe , Curry

在实际项目中,多对多关系通过中间表,看成两个一对多关联关系。

9.3 SQL数据表结构

-- drop table if exists user3;

-- 创建用户基本表
create table user(
	id int primary key auto_increment, -- 主键自增长
	username varchar(20) not null,
	birthday date,
	sex char(1) default '男',
	address varchar(50)
);

insert into user3 values (null, '侯大利','1990-10-24','男','江州');
insert into user3 values (null, '王大青','1992-11-12','女','秦阳');
insert into user3 values (null, '朱琳','1983-05-20','男','江州');
insert into user3 values (null, '田大甜','1993-03-22','女','阳州');

-- 查询数据
select * from user;

-- 用户信息表
create table user_info(
	id int primary key, -- 既是主键,又是外键
	height double, -- 身高厘米
	weight double, -- 体重公斤
	married tinyint, -- 是否结婚
	foreign key(id) references user3(id)
);

-- 插入用户数据
insert into user_info values(1,185,90,1),(2,170,60,0);

select * from user_info;

9.4 一对一关联

查询1号用户和他的扩展信息

扫描二维码关注公众号,回复: 12662179 查看本文章
select * from user u inner join user_info i on u.id = i.id where u.id=1

9.4.1 用户实体类

  • UserInfo类(创建一对一的关系)
package cn.guardwhy.domain;
/**
 * 用户拓展信息类
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserInfo {
    
    
    private Integer id; // 主键
    private Double height; // 身高
    private Double weight; // 体重
    private Boolean married; // 是否结婚
    private User user; // 用户的基本信息
}
  • User类(创建一对一的关系)
package cn.guardwhy.domain;

import java.sql.Date;

/**
 * 用户类
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    
    
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
    private UserInfo userInfo; // 对应的用户扩展信息
}

9.4.2 sqlMapConfig.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <!--在内部配置属性-->
    <properties resource="db.properties">
        <property name="jdbc.username" value="root"/>
        <property name="jdbc.password" value="root"/>
    </properties>

    <!--定义实体类别名-->
    <typeAliases>
        <package name="cn.guardwhy.domain"/>
    </typeAliases>

    <!-- 一个核心配置文件,可以配置多个运行环境,default默认使用哪个运行环境 -->
    <environments default="default">
        <!-- 其中的一个运行环境,通过id来进行标识-->
        <environment id="default">
            <!--事务管理器 -->
            <transactionManager type="JDBC"/>
            <!--数据源 -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

    <!--映射器-->
    <mappers>
        <package name="cn.guardwhy.dao"/>
    </mappers>
</configuration>

9.4.3 用户接口

package cn.guardwhy.dao;

import cn.guardwhy.domain.User;

public interface UserMapper {
    
    
    /**
     * 通过uid查找用户和拓展信息
     */
    User findUserAndInfo(int uid);
}

9.4.4 用户Mapper.xml

association标签:实现一对一关系

association标签的属性 说明
property 一对一对应的另一方实体类的属性名,如:userInfo
resultMap 指定另一方映射配置的id,如:用户扩展信息的映射
  1. 定义User的映射**userMap**,包含主键和所有的属性,无论属性名与列名是否相同。

  2. 定义用户信息的映射**userInfoMap**,包含主键和所有的属性,无论属性名与列名是否相同。

  3. 定义映射userAndInfoMap,extends继承于userMap,同时必须指定type属性

  4. 使用association定义一对一关联映射,指定:property、resultMap属性,将resultMap指定为userInfoMap

  5. 使用表连接查询:通过用户id查询用户和对应的用户扩展信息,查询结果映射为userAndInfoMap。

<?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="cn.guardwhy.dao.UserMapper">
    <!--1.创建User的映射-->
    <resultMap id="userMap" type="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"/>
    </resultMap>

    <!--2.创建UserInfo的映射-->
    <resultMap id="userInfoMap" type="userInfo">
        <!--映射主键-->
        <id property="id" column="id"/>
        <result property="height" column="height"/>
        <result property="weight" column="weight"/>
        <result property="married" column="married"/>
    </resultMap>

    <!--3.创建一对一的关联extends,将上面的映射关系复制过来-->
    <resultMap id="userAndInfoMap" type="user" extends="userMap">
        <!--一对一关联-->
        <association property="userInfo" resultMap="userInfoMap"/>
    </resultMap>

    <!--4.使用上面的一对一的映射-->
    <select id="findUserAndInfo" resultMap="userAndInfoMap" parameterType="int">
        select * from user3 u inner join user_info i on u.id = i.id where u.id = #{id}
    </select>
</mapper>

9.4.5 测试代码

查询输出用户和扩展信息

package cn.guardwhy.test;

import cn.guardwhy.dao.UserMapper;
import cn.guardwhy.domain.User;
import cn.guardwhy.utils.SessionFactoryUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class TestUserMapper {
    
    
    private static SqlSessionFactory factory;
    private SqlSession session;
    private UserMapper userMapper;

    // 1.创建会话对象,自动提交事务
    @Before
    public void begin(){
    
    
        session = SessionFactoryUtils.getSession();
        userMapper = session.getMapper(UserMapper.class);
    }

    // 2.测试代码
    @Test
    public void testFindUserAndInfo(){
    
    
        User user = userMapper.findUserAndInfo(1);
        System.out.println("用户信息:" + user);
        System.out.println("扩展信息:" + user.getUserInfo());
    }

    // 3.关闭会话
    @After
    public void end(){
    
    
        // 手动提交
        session.commit();
        session.close();
    }
}

9.4.6 执行结果

9.5 一对多关联

9.5.1 订单模型

9.5.2 SQL数据表结构

-- 创建订单表
create table order_form(
    oid int primary key auto_increment ,   -- 主键
    user_id int not null,   -- 用户id,外键
    number varchar(20),   -- 订单编号
    create_time datetime,  -- 下单时间
    note varchar(100),   -- 备注
    foreign key(user_id) references user(id)   -- 外键约束,关联主表的主键
);

-- 添加订单数据
insert into order_form values(null, 1,'10001001', now(), '请提前安装'),(null, 1,'10001002', now(), '包邮'),(null, 1,'10001003', now(), '选择红色');
insert into order_form values(null, 2,'10001004', now(), '购买多件'),(null, 2,'10001005', now(), '安全带');
-- 查询订单表
select * from order_form;

9.5.3 数据表关系

9.5.4 用户实体类

  • OrderForm(创建一对多的关系)
package cn.guardwhy.domain;

import java.sql.Timestamp;

/**
 * 订单实体类
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OrderForm {
    
    
    private Integer oid; // 主键
    private Integer userId; // 外键
    private String number; // 订单号
    private Timestamp createTime; // 下单时间
    private String note; // 备注信息
    private User user; // 用户信息
}
  • User(创建一对多的关系)
package cn.guardwhy.domain;

import java.sql.Date;
import java.util.List;

/**
 * 用户类
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    
    
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;

    private UserInfo userInfo; // 对应的用户扩展信息
    private List<OrderForm> orders; // 对应所有的订单信息
}

9.5.5 用户接口

/**
  * 查询全部用户数据并且查询用户的所有订单数据
*/
User findUserAndOrders(int uid);

9.5.6 用户Mapper.xml

collection标签:用来配置1对多的关联映射

collection的属性 说明
property 多方属性的名字,如:orders
javaType 多方的属性类型,可以省略。如:list
ofType 集合中每个元素的类型,如:orderForm
resultMap 多方的映射,如:订单映射 orderMap

步骤

  1. 定义订单的映射orderMap
  2. 配置用户到订单的一对多关联关系userOrdersMap,继承于userMap
  3. collection:配置一对多关联关系,指定property,ofType,resultMap为orderMap
  4. 查询某个用户,并且查询关联的多个订单信息,结果为userOrdersMap
<?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="cn.guardwhy.dao.UserMapper">
    <!--创建User的映射-->
    <resultMap id="userMap" type="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"/>
    </resultMap>

    <!--1.2创建UserInfo的映射-->
    <resultMap id="userInfoMap" type="userInfo">
        <!--映射主键-->
        <id property="id" column="id"/>
        <result property="height" column="height"/>
        <result property="weight" column="weight"/>
        <result property="married" column="married"/>
    </resultMap>

    <!--1.3 创建一对一的关联extends,将上面的映射关系复制过来-->
    <resultMap id="userAndInfoMap" type="user" extends="userMap">
        <!--一对一关联-->
        <association property="userInfo" resultMap="userInfoMap"/>
    </resultMap>

    <!--1.4 使用上面的一对一的映射-->
    <select id="findUserAndInfo" resultMap="userAndInfoMap" parameterType="int">
        select * from user u inner join user_info i on u.id = i.id where u.id = #{id}
    </select>

    <!--创建订单的映射-->
    <resultMap id="orderMap" type="orderForm">
        <id property="oid" column="oid"/>
        <result property="userId" column="user_id"/>
        <result property="number" column="number"/>
        <result property="createTime" column="create_time"/>
        <result property="note" column="note"/>
    </resultMap>

    <!--配置一对多的映射-->
    <resultMap id="userOrdersMap" type="user" extends="userMap">
        <!--
           property: 多方的属性名
           javaType:多方的属性类型
           ofType: 集合中每个元素的类型
           resultMap:多方映射
       -->
        <collection property="orders" javaType="list" ofType="orderForm" resultMap="orderMap"/>
   </resultMap>
    <!--一对多的关联查询-->
   <select id="findUserAndOrders" resultMap="userOrdersMap" parameterType="int">
       select * from user u inner join order_form o on u.id = o.user_id where u.id=#{id}
   </select>
</mapper>

9.5.7 测试代码

// 3.查询1号用户的所有订单
@Test
public void testFindUserAndOrders(){
    
    
    User user = userMapper.findUserAndOrders(1);
    System.out.println("用户信息:" + user);
    List<OrderForm> orders = user.getOrders();
    System.out.println("用户订单信息如下:" );
    for (OrderForm order : orders){
    
    
        System.out.println(order);
    }
}

9.5.8 执行结果

9.6 多对多关联

多对多关联关系,可以通过中间表看成两个双向的一对多关联关系。

9.6.1 关联模型

9.6.2 SQL数据表结构

-- 创建角色表
create table role(
	role_id int primary key auto_increment comment '角色id(主键)',
	role_name varchar(32) not null comment '角色名称',
	role_detail varchar(100) default null comment '角色描述'
);

-- 插入角色记录
insert into role(role_name, role_detail) values('局长', '公安局的管理者');
insert into role(role_name, role_detail) values('普通刑警', '刑侦破案');
insert into role(role_name, role_detail) values('法医', '协助刑警破案');
insert into role(role_name, role_detail) values('支队长', '刑警管理者');

select * from role;

-- 创建用户的角色中间表
create table user_role(
	user_id int not null comment '用户id',
	role_id int not null comment '角色id',
	primary key(user_id, role_id), -- 复合主键
	foreign key(user_id) references user(id),
	foreign key(role_id) references role(role_id)
);

insert into user_role(user_id, role_id) values(1,1);
insert into user_role(user_id, role_id) values(2,2);
insert into user_role(user_id, role_id) values(6,2);
insert into user_role(user_id, role_id) values(1,3);
insert into user_role(user_id, role_id) values(2,1);
insert into user_role(user_id, role_id) values(2,4);

-- 查询用户角色中间表
select * from user_role;

-- 查询1号用户有哪些角色
select *from user u inner join user_role ur on u.id = ur.user_id inner join 
role r on r.role_id = ur.role_id where u.id = 1;

9.6.3 角色实体类

Role(角色实体类)

package cn.guardwhy.domain;

import java.util.List;

/**
 角色实体类
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Role {
    
    

    private Integer roleId;
    private String roleName;
    private String roleDetail;

    private List<User> users;  //对应多个用户
}

User(创建多对多的关系)

package cn.guardwhy.domain;

import java.sql.Date;
import java.util.List;

/**
 * 用户类
*/

@Data
@NoArgsConstructor
@AllArgsConstructor

public class User {
    
    
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;

    private UserInfo userInfo; // 对应的用户扩展信息
    private List<OrderForm> orders; // 对应所有的订单信息
    private List<Role> roles; // 对应多个角色
}

9.6.4 用户接口类

/**
 * 通过uid查找用户和他的所有角色
*/
User findRolesByUserId(int uid);

9.6.5 用户Mapper.xml

  1. 定义User的映射配置userMap(已经配置)
  2. 定义角色的映射roleMap,配置主键和所有的属性
  3. 定义一个用户对象对应多个角色userRolesMap,继承于userMap
  4. 使用collection关联映射,指定property,javaType,ofType,resultMap为roleMap
  5. 定义查询findUserAndInfo,映射结果是:userRolesMap
<?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="cn.guardwhy.dao.UserMapper">
    <!--创建User的映射-->
    <resultMap id="userMap" type="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"/>
    </resultMap>
    
    <!--3.1 配置角色的映射-->
    <resultMap id="roleMap" type="role">
        <id property="roleId" column="role_id"/>
        <id property="roleName" column="role_name"/>
        <id property="roleDetail" column="role_Detail"/>
    </resultMap>

    <!--3.2 配置多对多的映射-->
    <resultMap id="userRolesMap" type="user" extends="userMap">
        <!--
           property: 多方的属性名
           javaType:多方的属性类型
           ofType: 集合中每个元素的类型
           resultMap:多方映射
       -->
        <collection property="roles" javaType="list" ofType="role" resultMap="roleMap"/>
    </resultMap>

    <!--3.3 查询某个用户对应的角色-->
    <select id="findRolesByUserId" resultMap="userRolesMap" parameterType="int">
        select *from user u inner join user_role ur on u.id = ur.user_id
        inner join role r on r.role_id = ur.role_id where u.id = #{id};
    </select>
</mapper>

9.6.6 测试代码

// 多对多关联查询
@Test
public void testFindRolesByUserId(){
    
    
    User user = userMapper.findRolesByUserId(1);
    System.out.println("用户信息:" + user);
    List<Role> roles = user.getRoles();
    System.out.println("用户角色如下: ");
    for(Role role : roles){
    
    
        System.out.println(role);
    }
}

9.6.7 执行结果

猜你喜欢

转载自blog.csdn.net/hxy1625309592/article/details/113528180