Mybatis中的关系映射 一对多 和多对多

创建两张表格   player 和team  

 player表

CREATE TABLE `player` (
  `playerId` int NOT NULL,
  `playerName` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,
  `playerNum` int DEFAULT NULL,
  `teamId` int DEFAULT NULL,
  PRIMARY KEY (`playerId`),
  KEY `teamId` (`teamId`),
  CONSTRAINT `player_ibfk_1` FOREIGN KEY (`teamId`) REFERENCES `team` (`teamId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

team表

CREATE TABLE `team` (
  `teamId` int NOT NULL AUTO_INCREMENT COMMENT '球队ID',
  `teamName` varchar(50) DEFAULT NULL COMMENT '球队名称',
  `location` varchar(50) DEFAULT NULL COMMENT '球队位置',
  `createTime` date DEFAULT NULL COMMENT '球队建立时间',
  PRIMARY KEY (`teamId`)
) ENGINE=InnoDB AUTO_INCREMENT=1013 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

插入数据如下

引出问题,mybatis如何进行多表连接查询

比如根据player表的teamId查询出所有球员的信息,在此情况下如何获取球员对于的球队信息?

1 对一关系的映射

实体类

public class Player {
private Integer playerId;
private String playerName;
private Integer playerNum;
private Integer teamId;
//多对一的体现:多方持有一方的对象 要有get方法
private Team team1;//关联对象--多个球员可以属于同一个球队;
private Team team2;//关联对象--多个球员可以属于同一个球队;
private Team team3;//关联对象--多个球员可以属于同一个球队;
//省略set get 和toString方法

}

mapper接口

public interface PlayerMapper {
      List<Player>  queryById1(int playerId);
    List<Player> queryById2(int playerId);
    List<Player> queryById3(int playerId);
}

对一映射方式1:通过关联对象打点调用属性的方式

  要求:两表的连接查询

 <select id="queryById1" resultMap="JoinTeamResult1">
        select * from player p inner join team t on p.teamId=t.teamId
        where t.teamId=#{id}
    </select>
    <resultMap id="baseResultMap" type="com.kkb.pojo.Player">
        <id column="playerId" property="playerId"></id>
        <result column="playerName" property="playerName"></result>
        <result column="playerNum" property="playerNum"></result>
        <result column="teamId" property="teamId"></result>
    </resultMap>
    <!-- 方式1:通过关联对象打点调用属性的方式
 要求:连接查询
 如果连接查询,一般单独定义resultMap
 extends="表示继承的其他的resultMap的id"
 -->
    <resultMap id="JoinTeamResult1" type="com.kkb.pojo.Player" extends="baseResultMap">
        <id column="teamId" property="team1.teamId"></id>
        <result column="teamName" property="team1.teamName"></result>
        <result column="location" property="team1.location"></result>
        <result column="teamName" property="team1.teamName"></result>
        <result column="createTime" property="team1.createTime"></result>
    </resultMap>

测试类

package com.kkb.test;

import com.kkb.mapper.PlayerMapper;
import com.kkb.pojo.Player;
import com.kkb.utils.MybatisUtil;
import org.junit.Test;

import java.util.List;

public class PlayerTest {
     private PlayerMapper playerMapper = MybatisUtil.getSqlSession().getMapper(PlayerMapper.class);

  
     @Test
    public  void test01(){
         List<Player> players = playerMapper.queryById1(1005);
         for (Player player : players) {
             System.out.println(player);
         }
     }

    @Test
    public void test02(){
        Player player = playerMapper.queryById2(1005);
         for (Player player : players) {
             System.out.println(player);
         }
}
    @Test
    public void test03(){
    Player player = playerMapper.queryById3(1005);
     for (Player player : players) {
             System.out.println(player);
         }
    }


}

 对一映射方式2:直接引用关联对象的Mapper映射

要求:

1、两表的连接查询
2、关联对象中已经存在被引用的resultMap

<select id="queryById2" resultMap="JoinTeamResult2">
        select * from player p inner join team t on p.teamId=t.teamId
        where t.teamId=#{id}
    </select>
<!--方式2:直接引用关联对象的Mapper映射:要求连接查询
property="关联对象的属性名"
javaType="关联对象的类型"
resultMap="关联对象的命名空间中的resultMap"
-->
<resultMap id="JoinTeamResult2" type="com.kkb.pojo.Player" extends="baseResultMap">
<association property="team2" javaType="com.kkb.pojo.Team"
resultMap="com.kkb.mapper.TeamMapper.baseResultMap"></association>
</resultMap>

 teamMapper.xml中的baseResultMap  

 <resultMap id="baseResultMap" type="com.kkb.pojo.Team">
        <id column="teamId" property="teamId"  javaType="int"></id>
        <result column="teamName" property="teamName"  javaType="string"></result>
        <result column="location" property="location"  javaType="string"></result>
        <result column="createTime" property="createTime"  javaType="date"></result>
    </resultMap>

测试结果:

 

对一映射方式3:直接引用关联对象的单独查询的方法

要求:

1、不需要两表的连接查询
2、关联对象中已经存在被引用的查询方法(接口类中的方法)

就是分两步查先根据playerId查询出来的信息,再根据association标签中column属性指定第二次查询的列作为条件进行二次查询。

<select id="queryById3" resultMap="JoinTeamResult3">
    select * from player where teamId=#{id}
</select>

 <resultMap id="baseResultMap" type="com.kkb.pojo.Player">
        <id column="playerId" property="playerId"></id>
        <result column="playerName" property="playerName"></result>
        <result column="playerNum" property="playerNum"></result>
        <result column="teamId" property="teamId"></result>
    </resultMap>

<!--方式3:直接引用关联对象的单独查询的方法:要求:关联对象的Maper中必须要求有单独的查询方法
property="关联对象的属性名"
javaType="关联对象的类型"
select="关联对象的单独查询的语句"
column="外键列"
-->
<resultMap id="JoinTeamResult3" type="Player" extends="baseResultMap">
    <association property="team3" javaType="Team"
    select="com.kkb.mapper.TeamMapper.queryById" column="teamId"></association>
  </resultMap>

teamMapper接口中对应的方法。 

  Team queryById(Integer teamId);

teamMapper.xml中的方法查询语句 

  <select id="queryById" parameterType="int" resultType="com.kkb.pojo.Team">

    select * from team where teamId=#{id}
</select>

测试结果:

 可以看到进行了两次查询

总结

开发中常用到第二种和第三种方式,其实第三种方式就是分两次查询,这一点也可以在service层次做到。

 对多关系的映射

修改实体类Team.java:

public class Team {
    private Integer teamId;
    private String teamName;
    private String location;
    private Date createTime;
    //一对多的体现:一方持有多方的对象  分两种方法介绍
    private List<Player> playerList1;//关联对象--一个球队可以拥有多个球员
    private List<Player> playerList2;//关联对象--一个球队可以拥有多个球员

    //get  和set  方法  toString方法自行补充
}

TeamMapper.java接口中添加方法:

public interface TeamMapper {
    Team queryById1(int teamId);
    Team queryById2(int teamId);
}

PlayerMapper.java接口中添加方法:  第二种方法要用到

public interface PlayerMapper {    
    List<Player> queryByTeamId(int teamId);
}

PlayerMapper.xml添加如下内容:

<select id="queryByTeamId" resultType="Player">
    select * from player where teamId=#{id}
</select>

方式1:连接查询+引用关联对象的结果映射

一步查询  需要inner join进行连接查询

 方式2:引用关联对象的单独查询的方法

分两部查询   需要引用的其他类的方法进行二次查询

TeamMapper.xml添加

<select id="queryById1" resultMap="joinResult1">
    select * from team t join player p
    on t.teamId=p.teamId where t.teamId=#{id};
</select>
<select id="queryById2" resultMap="joinResult2">
    select * from team where teamId=#{id};
</select>
<!--方式1:
对多的连接查询:对多使用collection
property="关联对象的集合名称"
javaType="关联对象的集合类型"
ofType="关联对象的集合的泛型"
resultMap="引用关联对象的结果映射"
-->
<resultMap id="joinResult1" type="Team" extends="baseResultMap">
    <collection property="playerList1" javaType="java.util.ArrayList" ofType="Player"
    resultMap="com.kkb.mapper.PlayerMapper.baseResultMap"></collection>
</resultMap>
<!--方式2:
对多的连接查询:对多使用collection
property="关联对象的集合名称"
javaType="关联对象的集合类型"
ofType="关联对象的集合的泛型"
select="引用关联对象的单独查询的方法":使用的前提是关联对象中该方法可用
column="引用关联对象的单独查询的方法的参数,一般是外键"
-->
<resultMap id="joinResult2" type="Team" extends="baseResultMap">
    <collection property="playerList2" javaType="java.util.ArrayList"
    select="com.kkb.mapper.PlayerMapper.queryByTeamId" column="teamId"></collection>
</resultMap>

测试:

public class TestPlayerMapper {
TeamMapper teamMapper=MybatisUtil.getSqlSession().getMapper(TeamMapper.class);
     /**
     * 多关系查询   连接查询
     */
    @Test
    public void test04() {
        Team team = teamMapper.queryById1(1005);
        System.out.println(team);
        List<Player> playerList1 = team.getPlayerList1();
        for (Player player : playerList1) {
            System.out.println(player);
        }
    }

    /**
     * 多关系查询    两次查询
     */
    @Test
    public void test05() {
        Team team = teamMapper.queryById2(1003);
        System.out.println(team);
        List<Player> playerList2 = team.getPlayerList2();
        for (int i = 0; i < playerList2.size(); i++) {
            System.out.println(playerList2.get(i));
        }
    }
   
}

测试结果:

tset04

 tset05

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值