SSM—mybatis框架-结果处理-resultMap定义-association-collection

1、结果处理

1.1、简单类型输出映射!

简单类型,比如int,注意哦,一些类型的resultType,mybatis已经帮我们定义好了,我们直接用人家定义好的就行了!

详情见:https://mybatis.org/mybatis-3/zh/configuration.html#typeAliases

public interface CarsMapper {

    int findAllCars();
}

<select id="findAllCars" resultType="int">
    select count(*) from cars
</select>
@Test
public void findAllCars(){
    System.out.println(mapper.findAllCars());
}

[DEBUG] 2021-04-08 16:35:02,038 ==> Preparing: select count(*) from cars
[DEBUG] 2021-04-08 16:35:02,084 ==> Parameters:
[DEBUG] 2021-04-08 16:35:02,233 <== Total: 1
3

1.2、pojo对象输出映射!

之前,我们测试了,如果列名和我们的属性名一致的话,那么mybatis会自动映射,将查询结果封装到对象中。

那如果我们数据库中的列名是game_desc呢? 单独列名desc是通不过的,那我们只能起game_desc,那我们pojo的Game对象呢,总不能起game_desc把,这样就不规范了,我们标准是不是驼峰啊,gameDesc,那么问题来了,我们按照原来的方法是不是就映射不了啊,mybatis虽然厉害,但他也不能明白你的意思,对不对,他只能对队列名和属性名一致的来进行封装数据!

一种解决方法是我们在mybatis-config.xml文件中配置

<setting name=“mapUnderscoreToCamelCase” value=“true”/>,

这个时候,他才会为我们自动映射!

那好,我们来测试一下

创建game表

CREATE TABLE game(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(10),
	game_desc VARCHAR(10)
)

创建Game实体类

看不懂注解,请移位:1.4.3小节!

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Game {
    private int id;
    private String name;
    private String gameDesc;
}

GameMapper接口!

public interface GameMapper {

    List<Game> queryAllGameInfo();

}

GameMapper.xml配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tian.mapper.GameMapper">

    <select id="queryAllGameInfo" resultType="game">
        select * from game
    </select>

</mapper>

记得一定要在mapper注册GameMapper.xml ,一定要记得!!!

测试

@Test
public void queryAllGameInfos(){
    System.out.println(gameMapper.queryAllGameInfo());
}

结果! 是不是,我们的gameDesc经过配置后,也可以封装到poji对象了!

[DEBUG] 2021-04-08 16:57:33,651 ==> Preparing: select * from game
[DEBUG] 2021-04-08 16:57:33,687 ==> Parameters:
[DEBUG] 2021-04-08 16:57:33,724 <== Total: 4
[Game(id=1, name=lol, gameDesc=塔防类), Game(id=2, name=cf, gameDesc=射击类), Game(id=3, name=dnf, gameDesc=地下类), Game(id=4, name=qq, gameDesc=聊天类)]

如果我们去了呢,来试下嘛,肯定是有问题的,这不用说!

看嘛,是不是获取不到gameDesc, gameDesc=null

[DEBUG] 2021-04-08 17:00:39,544 ==> Preparing: select * from game
[DEBUG] 2021-04-08 17:00:39,588 ==> Parameters:
[DEBUG] 2021-04-08 17:00:39,619 <== Total: 4
[Game(id=1, name=lol, gameDesc=null), Game(id=2, name=cf, gameDesc=null), Game(id=3, name=dnf, gameDesc=null), Game(id=4, name=qq, gameDesc=null)]

1.3、定义resultMap

首先再学resultMap之前,思考一下我们什么要定义resultMap,定义它是要来解决与什么的?

  • 在我们多表关联查询的时候,如果不加别名,查询的结果是不是可能有重复,我们自己写的可能不会太懵,那别人来看呢,别人调试一下你的代码,唉,这什么啊,为什么查出来有两个id,name啊,这是那个的name,id啊!
  • 诶,这个时候问题就很严重了,起了别名是不是和数据库的属性又不对应了,即使我们上边设置了<setting name=“mapUnderscoreToCamelCase” value=“true”/> ,但是还是保不齐不发建立映射关系,那这个时候我们需要定义一个resultMap来帮我们解决这个问题!

案例

创建表 person,game如下

CREATE TABLE person(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(10),
	game_id INT,
	CONSTRAINT game_id_fk FOREIGN KEY(game_id) REFERENCES game(id)
)
	
	
CREATE TABLE game(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(10),
	game_desc VARCHAR(10)
)

Person实体类

看不懂注解,请移位:1.4.3小节!

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    private int id;
    private String name;
    private Game game;
}

Game实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Game {
    private int id;
    private String name;
    private String gameDesc;
}

我们先来跑一下不加别名的sql查询

SELECT
  p.id,
  p.name,
  g.id,
  g.name,
  g.game_desc game_Desc
FROM
  person p
  LEFT JOIN game g
    ON p.game_id = g.id
WHERE p.id = 1

是不是一头雾水啊,人都傻了!

在这里插入图片描述

我们起别名之后,就豁然开朗了,瞬间清晰了很多有没有

在这里插入图片描述

清晰归清晰,我们查出来能映射吗? 我们查询最终是以别名为准,别名和我们pojo属性一致吗?

  • 很显然,并不一致,这个时候就有小伙伴说了,诶,我们将person属性设置的和别名一致不就好了吗,
    • 答案毋庸置疑是可以的,但是你考虑过我们如果不只查这个表呢,我们又该怎么办,是不是还映射不出来,那这个时候,我们显然选择映射前者即字段名和属性名一致,我们定义resultMap解决映射!

ok我们来写查询语句!

PersonMapper接口

public interface PersonMapper {

    List<Person> queryAll();

}

PersonMapper.xml文件

  • select标签中的id对应我们接口中的方法名
  • select标签中的resultMap对应我们定义的resultMap的id
  • resultMap的type对应我们查的表对应的java实体类类型
  • person表关联game表,我们association标签是用来封装game对象的
  • association中的property对应person类中的 private Game game; 属性 即game
  • association中javaType对应java实体类类型
  • id标签的column,很明显,对应数据库列名,
  • id标签的property,那就对应实体类中的属性喽!
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.tian.mapper.PersonMapper">

    <resultMap id="queryAllPersonInfo" type="Person">
        <id column="pid" property="id"/>
        <id column="pname" property="name"/>
        <!-- 封装game对象 -->
        <association property="game" javaType="Game">
            <id column="gid" property="id"/>
            <id column="gname" property="name"/>
            <id column="game_desc" property="gameDesc"/>
        </association>
    </resultMap>

    <select id="queryAll" resultMap="queryAllPersonInfo" >
        SELECT
          p.id pid,
          p.name pname,
          g.id gid,
          g.name gname,
          g.game_desc game_Desc
        FROM
          person p
          LEFT JOIN game g
            ON p.game_id = g.id
        WHERE p.id=2
    </select>

</mapper>

至此,我们就写完了,来测试一下

bingo! 我们的值是不是封装到了我们的实体类中,也就是说我们的列名和属性达到了映射!

[DEBUG] 2021-04-08 17:24:08,277 ==> Preparing: SELECT p.id pid, p.name pname, g.id gid, g.name gname, g.game_desc game_Desc FROM person p LEFT JOIN game g ON p.game_id = g.id WHERE p.id=2
[DEBUG] 2021-04-08 17:24:08,311 ==> Parameters:
[DEBUG] 2021-04-08 17:24:08,338 <== Total: 1
[Person(id=2, name=张三, game=Game(id=2, name=cf, gameDesc=射击类))]

1.4、resultMap使用(association,collection)注意!

当我们关联查询时候

  • 如果实体类封装的是对象,我们使用association,

  • 当我们封装的是对象集合的时候,用collection,

1.4.1、association

案例!

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    private int id;
    private String name;
    private Game game; // 对象!
}

这个时候我们得用association

如果你非得对象用collection,会出现下述错误:简单的说就是注入不进去!用association就好了!

org.apache.ibatis.exceptions.PersistenceException:

Error querying database. Cause: org.apache.ibatis.executor.ExecutorException: Error instantiating collection property for result ‘game’. Cause: org.apache.ibatis.reflection.ReflectionException: Could not set property ‘game’ of ‘class com.tian.pojo.Person’ with value ‘[]’ Cause: java.lang.IllegalArgumentException: argument type mismatch

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

<mapper namespace="com.tian.mapper.PersonMapper">

    <resultMap id="queryAllPersonInfo" type="Person">
        <id column="pid" property="id"/>
        <id column="pname" property="name"/>
        <!-- 封装game对象 -->
        <association property="game" javaType="Game">
            <id column="gid" property="id"/>
            <id column="gname" property="name"/>
            <id column="game_desc" property="gameDesc"/>
        </association>
    </resultMap>

    <select id="queryAll" resultMap="queryAllPersonInfo" >
        SELECT
          p.id pid,
          p.name pname,
          g.id gid,
          g.name gname,
          g.game_desc game_Desc
        FROM
          person p
          LEFT JOIN game g
            ON p.game_id = g.id
        WHERE p.id=2
    </select>

</mapper>

安全通过!

[DEBUG] 2021-04-08 17:33:11,578 ==> Preparing: SELECT p.id pid, p.name pname, g.id gid, g.name gname, g.game_desc game_Desc FROM person p LEFT JOIN game g ON p.game_id = g.id WHERE p.id=2
[DEBUG] 2021-04-08 17:33:11,614 ==> Parameters:
[DEBUG] 2021-04-08 17:33:11,636 <== Total: 1
[Person(id=2, name=张三, game=Game(id=2, name=cf, gameDesc=射击类))]

1.4.2、collection

当我们用的是对象的集合时,注意,这里 写法有些区稍稍不一样!

我们管理查询的时候,需要变动一下,由原来的 javaType=“Game” 变为 --> javaType=“list” ofType=“Game”

  • javaType是我们 private List game; 返回的类型,list已经返回已经被mybatis定义了,我们直接小写list即可,或者 java.util.List ,写全类名!

  • ofType是 private List<Game> game; 的泛型,即关联表映射的pojo类类型!

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    private int id;
    private String name;
    private List<Game> game;   // 对象的集合
}

这里我们得用collection

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

<mapper namespace="com.tian.mapper.PersonMapper">

    <resultMap id="queryAllPersonInfo" type="Person">
        <id column="pid" property="id"/>
        <id column="pname" property="name"/>
        <!-- 封装game集合 -->
        <collection property="game" javaType="list" ofType="Game">
            <id column="gid" property="id"/>
            <id column="gname" property="name"/>
            <id column="game_desc" property="gameDesc"/>
        </collection>
    </resultMap>

    <select id="queryAll" resultMap="queryAllPersonInfo" >
        SELECT
          p.id pid,
          p.name pname,
          g.id gid,
          g.name gname,
          g.game_desc game_Desc
        FROM
          person p
          LEFT JOIN game g
            ON p.game_id = g.id
        WHERE g.id=2
    </select>

</mapper>

如果我们用association的话,还是会出一样的错误,出现这类错误,我们就能定位到是哪里出现了错误!

Cause: org.apache.ibatis.reflection.ReflectionException: Could not set property ‘game’ of ‘class com.tian.pojo.Person’ with value ‘Game(id=2, name=cf, gameDesc=射击类)’ Cause: java.lang.IllegalArgumentException: argument type mismatch

为了确保准确,这里我们查询条件换为g.id = 2,

[DEBUG] 2021-04-08 17:36:36,243 ==> Preparing: SELECT p.id pid, p.name pname, g.id gid, g.name gname, g.game_desc game_Desc FROM person p LEFT JOIN game g ON p.game_id = g.id WHERE g.id=2
[DEBUG] 2021-04-08 17:36:36,278 ==> Parameters:
[DEBUG] 2021-04-08 17:36:36,405 <== Total: 2
[Person(id=2, name=张三, game=[Game(id=2, name=cf, gameDesc=射击类)]), Person(id=5, name=李四, game=[Game(id=2, name=cf, gameDesc=射击类)])]

1.5、懒加载

  • 需要查询关联信息时,使用 Mybatis 懒加载特性可有效的减少数据库压力,

  • 首次查询只查询主表信息,关联表的信息在用户获取时再加载。

  • Mybatis 一对一关联的 association 和一对多的 collection 可以实现懒加 载。

  • 懒加载时要使用 resultMap,不能使用 resultType。

懒加载

设置项描述允许值默认值
lazyLoadingEnabled是否开启懒加载模式true | falsefalse

启动懒加载

在mybatis-config.xml中的settings标签中设置

<setting name="lazyLoadingEnabled" value="true"/>

在关联表即从表设置

 fetchType="lazy"   

如果是这样,表示不启动懒加载

fetchType="eager"
<association property="game" javaType="Game" fetchType="lazy" 

select="findGameByID" column="game_id"></association> 

(1). Select:指定关联查询懒加载对象的 Mapper Statement ID 为

findGameByID

(2). column=“game_id”:关联查询时将 game_id列的值传入 findGameByID,

并将 findGameByID查询的结果映射到 Person的 Game属性中

(3).collection 和 association 都需要配置 select 和 column 属性,两者配置方法

相同

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值