SSM—mybatis框架-结果处理-resultMap定义-association-collection
文章目录
- 1、结果处理
- 1.1、简单类型输出映射!
- 1.2、pojo对象输出映射!
- 1.3、定义resultMap
- 1.4、resultMap使用(association,collection)注意!
- 1.4.1、association
- 1.4.2、collection
- 1.5、懒加载
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 mapperPUBLIC "-//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查询
SELECTp.id,p.name,g.id,g.name,g.game_desc game_Desc
FROMperson pLEFT JOIN game gON 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 mapperPUBLIC "-//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" >SELECTp.id pid,p.name pname,g.id gid,g.name gname,g.game_desc game_DescFROMperson pLEFT JOIN game gON p.game_id = g.idWHERE 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 mapperPUBLIC "-//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" >SELECTp.id pid,p.name pname,g.id gid,g.name gname,g.game_desc game_DescFROMperson pLEFT JOIN game gON p.game_id = g.idWHERE 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 mapperPUBLIC "-//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" >SELECTp.id pid,p.name pname,g.id gid,g.name gname,g.game_desc game_DescFROMperson pLEFT JOIN game gON p.game_id = g.idWHERE 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 | false | false |
启动懒加载
在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 属性,两者配置方法
相同
SSM—mybatis框架-结果处理-resultMap定义-association-collection相关推荐
- 【MyBatis框架】配置文件-resultMap总结
resultMap总结 resultType: 作用: 将查询结果按照sql列名pojo属性名一致性映射到pojo中. 场合: 常见一些明细记录的展示,比如用户购买商品明细,将关联查询信息全部展示在页 ...
- SSM—mybatis框架-注解开发-动态sql(where,set,trim,choose,when,foreach)-模糊查询写法-特殊符号处理-缓存
文章目录 2.0.注解 2.1.动态sql 2.1.1.where 2.1.2.set 2.1.3.trim 2.1.3.1.trim的where 2.1.3.2.trim的set 2.1.4.1.c ...
- MyBatis框架学习 DAY_02:使用XML配置文件/多参数问题 / FOREACH /IF / #{}和${} / 创建SSM框架流程
XML文件配置SQL 1. 使用XML文件配置SQL语句 2. 关于多参数的问题 2. 练习 3. 动态SQL -- foreach 4. 动态SQL -- if 5. 关于#{}和${}格式的占位符 ...
- Mybatis 高级结果映射 ResultMap Association Collection
来源:http://www.verydemo.com/demo_c152_i1880.html MyBatis的创建基于这样一个思想:数据库并不是您想怎样就怎样的.虽然我们希望所有的数据库遵守第三范式 ...
- SSM之Mybatis框架高级
1.resultMap高级操作:联合查询操作 #1 一对一关联查询 例如:根据订单关联查询用户 输出映射: resultType:自定义一个拓展的的pojo resultMap: 这里的resultM ...
- SSM之Mybatis框架初步
1. SSH:Spring 中间层(容器框架,整合框架) Struct(控制层,Servlet) Hibernate(DAO,持久层框架) Structs2 Hibernate 两个重量级框架,入门 ...
- SSM之Mybatis框架
最近在学SSM框架,现在来简单介绍一下,SSM里的mybatis框架. 首先来介绍一下ORM 1.ORM简介 Object Relational Mapping:对象关系映射. 简单的理解:ORM是通 ...
- mybatis元素类型为 “resultMap“ 的内容必须匹配 “(constructor?,id *,result*,association报错解决
1.前言 太久没写这种套娃式的sql语句了,导致今天一写,直接给我整了个报错. 原因其实蛮简单的,mybatis的xml中的resultMap标签规定了内标签的顺序,写错了就会直接解析不出来,从而报错 ...
- (Spring+SpringMVC+MyBatis)SSM三大框架整合教程
目录 一.基本概念 1.Spring 2.SpringMVC 3.MyBatis 二.开发环境搭建 三.Maven Web项目创建 四.SSM整合 1.Maven引入需要的JAR包 2.Spring与 ...
最新文章
- 观点 | 转行人士如何在人工智能领域保持一定的竞争力?
- 递归和迭代的区别是什么,各有什么优缺点?
- 协程 线程 进程的一点理解
- TensorFlow、MXNet、Keras如何取舍? 常用深度学习框架对比
- 5去掉button按钮的点击样式_CSS实现复古按钮
- stm32 fatfs fopen err_disk__小型文件系统FatFS和LittleFS对比和区别
- CTFHub-Web-信息泄露
- 关于 V C++ 中 Error 6 fatal error C1075的解决办法
- Spring Cloud CLI简介
- Consider renaming one of the beans or enabling overriding by setting
- linux是发展历史,linux发展历史.doc.doc
- RSync实现文件同步备份配置详解
- c语言编写记账程序,C语言会计记账管理系统
- 倍福PLC通过CANOpen通信控制伺服
- WordPress优化攻略:全面提升WP网站速度仅需3个加速方法和1个插件
- (原)使用ass字幕文件通过ffmpeg给视频添加字幕的一些研究
- ATFX:美国通胀转折点已来,激进加息势将暂缓?
- 猫眼爬取专业评分的python技术
- 第14届蓝桥杯省赛真题剖析-2023年5月7日Scratch编程初级组
- 进阶:主流的cpu插槽类型详解