本篇主要内容如下:

  1. 简单一对一级联查询
  2. 嵌套结果与嵌套查询
  3. 一对多单向
  4. 缓存(了解)
  5. 延迟加载(了解)
  6. 鉴别器(自学)
  7. 调用存储过程
  8. 分页拦截
  9. 多形参问题

简单一对一级联查询

在实际项目中,经常是关联表的查询,比如:最常见到的一对一,一对多等。这些查询是如何处理的呢,这一讲就讲这个问题。前面节中介绍的都是单表映射的一些操作,然而在我们的实际项目中往往是用到多表映射。在 Java 实体对象对中,一对多可以根据 List 和 Set 来实现,两者在 mybitis 中都是通过 collection 标签来配合来加以实现。这篇介绍的是多表中的多对一表关联查询。

创建两张表,假设一个老师对应一个班级

CREATE TABLE `teacher` (`t_id` int(11) NOT NULL AUTO_INCREMENT,`t_name` varchar(20) DEFAULT NULL,PRIMARY KEY (`t_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;insert  into `teacher`(`t_id`,`t_name`) values (1,'张三');
insert  into `teacher`(`t_id`,`t_name`) values (2,'李四');CREATE TABLE `class` (`c_id` int(11) NOT NULL AUTO_INCREMENT,`c_name` varchar(20) DEFAULT NULL,`teacher_id` int(11) DEFAULT NULL,PRIMARY KEY (`c_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;insert  into `class`(`c_id`,`c_name`,`teacher_id`) values (1,'Java',1);
insert  into `class`(`c_id`,`c_name`,`teacher_id`) values (2,'UI',2);CREATE TABLE `student` (`s_id` int(11) NOT NULL AUTO_INCREMENT,`s_name` varchar(20) DEFAULT NULL,`class_id` int(11) DEFAULT NULL,PRIMARY KEY (`s_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
insert  into `student`(`s_id`,`s_name`,`class_id`) values (1,'AA',1);
insert  into `student`(`s_id`,`s_name`,`class_id`) values (2,'BB',1);
insert  into `student`(`s_id`,`s_name`,`class_id`) values (3,'CC',1);
insert  into `student`(`s_id`,`s_name`,`class_id`) values (4,'DD',2);
insert  into `student`(`s_id`,`s_name`,`class_id`) values (5,'EE',2);
insert  into `student`(`s_id`,`s_name`,`class_id`) values (6,'FF',2);

创建实体

public class Teacher {private int id;private String name;public class Classes {private int id;private String name;private Teacher teacher;

ClassesMapper.xml 查询将出现两张方式

方式一:级联查询

<resultMap id="classResultMap" type="cn.hx.mybatis.entity.Classes"><id column="c_id" property="id"/><result column="c_name" property="name"/><result column="t_id" property="teacher.id"/><result column="t_name" property="teacher.name"/>
</resultMap><select id="selectAll" resultMap="classResultMap">SELECT * FROM `class` c LEFT JOIN `teacher` t ON t.`t_id`=c.`teacher_id`
</select>

嵌套结果与嵌套查询

方式二:嵌套结果,使用嵌套结果映射来处理重复的联合结果的子集封装联表查询的数据(去除重复的数据)

<resultMap id="classResultMap2" type="cn.hx.mybatis.entity.Classes"><id column="c_id" property="id"/><result column="c_name" property="name"/><association property="teacher" javaType="cn.hx.mybatis.entity.Teacher"><id property="id" column="t_id"/><result property="name" column="t_name"/></association>
</resultMap><select id="selectAll" resultMap="classResultMap2">SELECT * FROM `class` c LEFT JOIN `teacher` t ON t.`t_id`=c.`teacher_id`
</select>

方式三:嵌套查询,通过执行另外一个 SQL 映射语句来返回预期的复杂类型

<select id="getClass2" resultMap="ClassResultMap2">select * from class
</select><resultMap type="cn.hx.mybatis.entity.Classes" id="ClassResultMap2"><id property="id" column="c_id"/><result property="name" column="c_name"/><association property="teacher" column="teacher_id" select="getTeacher"></association>
</resultMap><select id="getTeacher" parameterType="int" resultType="cn.hx.mybatis.entity.Teacher">SELECT t_id id, t_name name FROM teacher WHERE t_id=#{id}
</select>

association 定义关联对象的封装规则

select:表明当前属性是调用 select 指定的方法查出的结果。

column:指定将哪一列的值传给这个方法。

注意:$ 与 # 的区别:

#{} 使用占位符 ?的方式编译和发送 SQL;好处:防止 SQL 注入(推荐)

${} 将用户填入的参数直接拼接到 SQL。坏处:SQL 注入;

注意:使用 #{} 不能生成表名和字段名,所以在字段和表名处,必须使用 ${}。

将 #{id} 转成 ${id} 会报 There is no getter for property named 'id' in 'class java.lang.Integer' ,只需要将参数换成 ${_parameter} 或者换成更高的 3.5.6 即可。

一对多单向查询

实体类

public class Student {private int id;private String name;public class Classes {private int id;private String name;private Teacher teacher;private List<Student> students;

方式一:嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集

<select id="findAll" resultMap="ClassResultMap3">SELECT * FROM `class` c LEFT JOIN `student` s ON c.`c_id` =s.`class_id`
</select>
<resultMap type="cn.hx.mybatis.entity.Classes" id="ClassResultMap3"><id property="id" column="c_id"/><result property="name" column="c_name"/><collection property="students" ofType="cn.hx.mybatis.entity.Student"><id property="id" column="s_id"/><result property="name" column="s_name"/></collection>
</resultMap>

注意:ofType 指定 students 集合中的对象类型

方式二:嵌套查询,通过执行另外一个SQL映射语句来返回预期的复杂类型

<select id="findAll" resultMap="ClassResultMap4">select * from class
</select><resultMap type="cn.hx.mybatis.entity.Classes" id="ClassResultMap4"><id property="id" column="c_id"/><result property="name" column="c_name"/><collection property="students" ofType="cn.hx.mybatis.entity.Student"column="c_id" select="getStudent"></collection>
</resultMap><select id="getStudent" parameterType="int" resultType="cn.hx.mybatis.entity.Student">SELECT s_id id, s_name name FROM student WHERE class_id=#{id}
</select>

collection 定义关联集合类型的属性的封装规则

ofType:指定集合里面元素的类型

在 mybatis 中关联关系常用如下:

一对一    association       javaType

一对多    collection         ofType

缓存(了解)

1.一级缓存:基于 PerpetualCache 的 HashMap本地缓存,其存储作用域为 Session,当 Session clearCache  或 close 之后,该 Session中的所有 Cache 就将清空。 (默认开启)

2. 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为 Mapper(Namespace 命名空间),并且可自定义存储源,如 Ehcache。

3. 对于缓存数据更新机制,当某一个作用域(一级缓存 Session /二级缓存 Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被 clear。

一级缓存就是 Session 不关闭的情况下多次查询同一个对象不发 SQL,mybatis 默认开启一级缓存。

二级缓存通常需要在 *Mapper.xml 中添加一个 cache 标签 ,还要在 mybatis 配置文件中全局开启。

<settings><setting name="cacheEnabled" value="true"/>
</settings>

注意:第一个一级缓存关闭时会将数据刷入 SqlSessionFactory 另外一个 session 才能获取二级缓存内容,即前面的 session 必须关闭或 commit,后面的 session 才能获取。

SqlSessionFactory factory = MybatisUtils.getFactory();
SqlSession session1 = factory.openSession();
SqlSession session2 = factory.openSession();String statement = "com.ibaits.mapper.userMapper.getUser";
CUser user = session1.selectOne(statement, 1);
session1.commit();
System.out.println(user);user = session2.selectOne(statement, 1);
session2.commit();
System.out.println(user);

1. 映射语句文件中的所有 select 语句将会被缓存。

2. 映射语句文件中的所有 insert,update 和 delete 语句会刷新缓存。

3. 缓存会使用 Least Recently Used(LRU,最近最少使用的)算法来收回。

4. 缓存会根据指定的时间间隔来刷新。

5. 缓存会存储 1024 个对象

<cache
eviction="FIFO"  //回收策略为先进先出
flushInterval="60000" //自动刷新时间60s
size="512" //最多缓存512个引用对象
readOnly="true"/> //只读   

延迟加载(了解)

需要用到 cglib 做代理模式。使用如下方式导入 cglib 依赖

<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>2.2.2</version>
</dependency>

然后在全局配置文件加入

<!-- 全局配置参数 -->
<settings><!-- 延迟加载总开关 --><setting name="lazyLoadingEnabled" value="true" />    <!-- 设置按需加载 --><setting name="aggressiveLazyLoading" value="false" />
</settings>

如上配置,所有的嵌套查询就会延迟加载,但是所有的嵌套结果方式没有影响。

鉴别器(自学)

mybatis 可以使用 discriminator 判断某列的值,然后根据某列的值改变封装行为。

案例:封装 Employee

如果查出的是女生:就把部门信息查询出来,否则不查询;

如果是男生,把 last_name 这一列的值赋值给 email;

<resultMap type="cn.hx.mybatis.bean.Employee" id="MyEmpDis"><id column="id" property="id"/><result column="last_name" property="lastName"/><result column="email" property="email"/><result column="gender" property="gender"/><discriminator javaType="string" column="gender"><!--女生  resultType:指定封装的结果类型;不能缺少。/resultMap--><case value="0" resultType="employee"><association property="dept" select="cn.hszy.mybatis.mapper.DepartmentMapper.getDeptById"column="d_id"></association></case><!--男生 ;如果是男生,把last_name这一列的值赋值给email; --><case value="1" resultType="employee"><id column="id" property="id"/><result column="last_name" property="lastName"/><result column="last_name" property="email"/><result column="gender" property="gender"/></case></discriminator>
</resultMap>

调用存储过程(了解)

创建表和存储过程。

create table p_user(  id int primary key auto_increment,  name varchar(10),sex char(2)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into p_user(name,sex) values('A',"男");
insert into p_user(name,sex) values('B',"女");
insert into p_user(name,sex) values('C',"男");  

创建存储过程(查询得到男性或女性的数量,如果传入的是 0 就女性否则是男性)

DELIMITER $
CREATE PROCEDURE ges_user_count(IN sex_id INT, OUT user_count INT)
BEGIN
IF sex_id=0 THEN
SELECT COUNT(*) FROM p_user WHERE p_user.sex='女' INTO user_count;
ELSE
SELECT COUNT(*) FROM p_user WHERE p_user.sex='男' INTO user_count;
END IF;
END
$

调用存储过程

DELIMITER ;
SET @user_count = 0;
CALL ges_user_count(1, @user_count);
SELECT @user_count;

查询得到男性或女性的数量,如果传入的是0就女性否则是男性

mapper.xml

<mapper namespace="cn.hx.mybatis.test7.userMapper"><select id="getCount" statementType="CALLABLE" parameterMap="getCountMap">call ges_user_count(?,?)</select><parameterMap type="map" id="getCountMap"><parameter property="sex_id" mode="IN" jdbcType="INTEGER"/><parameter property="user_count" mode="OUT" jdbcType="INTEGER"/></parameterMap>
</mapper>

执行查询

Map<String, Integer> parameterMap = new HashMap<String, Integer>();
parameterMap.put("sex_id", 1);
parameterMap.put("user_count", -1);
session.selectOne(statement, parameterMap);
Integer result = parameterMap.get("user_count");
System.out.println(result);

分页拦截器

分页可以分为逻辑分页和物理分页。逻辑分页是我们的程序在显示每页的数据时,首先查询得到表中的 1000 条数据,然后成熟根据当前页的“页码”选出其中的 100 条数据来显示。

物理分页是程序先判断出该选出这 1000 条的第几条到第几条,然后数据库根据程序给出的信息查询出程序需要的 100 条返回给我们的程序。

mybatis 的分页通常在开发中有时借助第三方分页插件进行分页

添加如下两个第三方 jar 包

<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.0.0</version>
</dependency>

mybatis 配置文件加入插件

<plugins><plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>

在查询之前调用静态方法即可完成查询

@Test
public void testGetAll() {SqlSessionFactory factory = MybatisUtils.getFactory();   SqlSession session = factory.openSession();    String statement = "com.day03_mybaits.test2.userMapper.getAllUsers";Page<User> startPage = PageHelper.startPage(1, 12);List<User> list = session.selectList(statement);    session.close();for (User user : list) {System.out.println(user);}System.out.println(startPage.getPages());
}

Page 使用 json 序列化工具会导致其他属性(总页数,总条数)不见,可使用 PageInfo 弥补该问题

public PageInfo<MenuGroup> findAll(Integer page, Integer size) {Page<MenuGroup> objects = PageHelper.startPage(page, size);menuGroupMapper.selectByExample(new MenuGroupExample());return new PageInfo<>(objects);
}

多形参问题

由于 jdk7 之前通过反射无法获取方法参数的名字,jdk8 有该功能但是未开启。所以在接口中方法有多个参数时xml中无法正常识别。

List<Resource> queryAll(int start,int size,String name);

xml

<select id="queryAll" resultType="cn.hx.entity.Resource">select id, name, url, pid, create_time, update_time, order_number
from resource where name like #{name} limit #{start},#{size}
</select>

解决的办法有如下几个:

1.搜索打开 jdk8 反射获取参数名,或者升级更高版本的 jdk。

2.使用 [arg2, arg1, arg0, param3, param1, param2] 代替#{name}、#{start}和#{size}

3.像如下方式加入 mybatis 的注解 org.apache.ibatis.annotations.Param。

List<Resource> queryAll(@Param("start") int start,@Param("size") int size,@Param("name") String name);

级联查询Mybatis相关推荐

  1. springboot中mybatisplus基于注解的多对多级联查询

    mybatisplus使用注解多对多级联查询 mybatis提供了注解和xml两种方式配置我们的sql语句,我在接触使用的过程中更喜欢注解的方式,在我的上一个项目中,我全部使用mybatis注解去完成 ...

  2. mybatis一对多关联 创建_MyBatis多对多关联查询(级联查询)

    其实,MyBatis 没有实现多对多级联,这是因为多对多级联可以通过两个一对多级联进行替换. 例如,一个订单可以有多种商品,一种商品可以对应多个订单,订单与商品就是多对多的级联关系,使用一个中间表(订 ...

  3. mybatis 一对一 一对多 级联查询

    大家好,我是烤鸭: 今天分享一下关于mybatis的级联查询. 环境: mybatis   3.2.8 spring      4.1.9 1.   业务场景 在一个人申请某些账号或者权限的时候,比如 ...

  4. mybatis级联查询list_MyBatis手把手跟我做系列(四) ---级联查询与懒加载

    涉及到数据库的级联查询,那肯定就要提到一对一,一对多,多对多这样的表关系,以及java程序与之对应的类和类之间的表现形式,我这里主要通过一对多的表关系给大家介绍以下MyBatis里面对于级联关系的处理 ...

  5. MyBatis实现级联查询及逆向生成

    MyBatis实现级联查询及逆向生成 一,级联查询 1.级联查询 N-1 ​ 以多的一方为主表 接口 //级联查询 N-1List<Emp> selectEmp(Map map); 映射文 ...

  6. MyBatis级联查询

    文章目录 MyBatis级联查询 简介 一对一 创建数据库初始数据 创建实体类 创建Mapper类及XML 提供两次方式xml进行查询,代码均在StudentMapper .xml 分步查询 单步查询 ...

  7. mybatis 级联查询

    有时候我们的POJO对象经常不是一个简单的对象,往往存在着一对一或者一对多的关系.就如一个学生可以有一个班主任,有多门课程一样: public class StudentCourse {private ...

  8. MyBatis 的级联查询

    最近面试遇上一个问题就是问我MyBatis怎么级联查询 例如查询老师的时候把他的学生也查询出来 没回答上,回来自己看了看资料 找到方法了 记录下 我这里实现的是查询用户的时候把他的详情(一对一)和他的 ...

  9. layui表格显示后台的多表的级联查询(多对多,多对一)带mybatis级联查询源码,已解决

    在ssm和springboot项目中我们存在表与表之间一对多和多对多的情况,那么他们就要进行级联查询查询出相关联的数据,级联查询涉及到的问题就是在一个实体类中存在另一个实体类的对象(一对一)或者对象集 ...

最新文章

  1. 真香!20张图揭开「队列」的迷雾,一目了然
  2. 网站地图能给网站的优化带来什么好处
  3. 日本推出罩杯测量APP,罩杯大小一夹便知!
  4. Java HashSet源码解析
  5. Android7.0 PowerManagerService(2) WakeLock的使用及流程
  6. 魔力宝贝 服务器状态,魔力宝贝服务端standenemy的参数
  7. mysql简单的存储过程实例_mysql存储过程简单实例
  8. C++接收字符串数组_电脑编程 你该知道的字符知识 C语言程序设计字符数组全归纳...
  9. 沉浸式状态栏的简易实现
  10. 我眼中的Visual Studio 2010架“.NET研究”构工具
  11. centos samba 看不到共享目录_linux入门系列--文件共享之Samba和NFS
  12. java 爬取微信公众号文章 - 搜狗微信搜索
  13. 《SAP从入门到精通》——1.3 SAP R/3系统工作原理
  14. 5年部队服役结束,退伍后我做了一名码农
  15. Android如何实现超级棒的沉浸式体验
  16. Java写入txt文件内容
  17. wlh机器人_恐怖谷理论,人类对仿真机器人的天生恐惧
  18. Z-blogPHP蜘蛛访问日志统计插件+自动收集死链
  19. RIP协议。水平分割,毒性逆转,触发更新,抑制计时
  20. CDOJ1057-秋实大哥与花

热门文章

  1. 【linux】linux用户重置修改密码
  2. 揭秘美国总统奥巴马的专机、座驾和保镖
  3. icloud与mysql,在icloud中存储sqlite数据库?
  4. 2022年5大直播趋势
  5. 新库上线 | CnOpenData舆情云数据
  6. Python 获取LOL 皮肤(一)
  7. 硬核拆解 | 拓尔微65W 2C1A氮化镓多口快充
  8. 金蝶15.1安装完进入软件有徐少春的头像怎么隐藏
  9. 阿里云Windows无法在IE中下载文件的解决方法
  10. 程设:魔兽世界装备之二