MyBatis基于XML实现一对多、多对一的查询

646 阅读5分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第15天,点击查看活动详情。 在实际业务场景中,我们经常需要关联多张数据库表进行联合查询,有一对一、一对多等关系,这样我们在处理业务的时候就方便了很多,下面为来讲述相关复杂的查询方式。

首先先创建两个数据库表,一个是员工表,一个是部门表,员工表中存储部门表的ID,一个员工只能属于一个部门,一个部门可以有多个员工。

最终创建好的项目目录结构如下:

image.png

一、联合查询

1-1、使用普通映射方式实现->多对一

比如我们要查询下面这样的数据结构在mybatis中该如何实现呢? image.png

1-1-1、准备DTO存放Emp及Dept

按照mybatis的原则,Pojo中只存放和数据库对应的属性值,因此我们新建一个这两个类的DTO,如下:

image.png

1-1-2、准备EmpMapper.xml的查询语句

目前Emp和Dept的映射关系只是其中的一种方式,后面再介绍其他方式

image.png

1-1-3、准备接口Mapper

image.png

1-1-4、测试

image.png

1-2、使用association实现——>多对一

1-2-1、修改EmpMapper.xml

image.png

1-2-2、测试

image.png

1-2-3、association的特点

1-2-3-1、实现多对一映射关系

如上可以看到,通过association也可以实现多对一的映射关系。需要注意的是使用association
property 指定多对一中的“一”
javaType 指定“一”的类型

1-2-3-2、可以引用其他Mapper中的resultMap

最为特别的是,使用association,就不用再次映射表关系了,会节省很多代码量。如下:

image.png 另外 association中的reusltMap指定的内容如果是跨Mapper映射文件,需要加上另外一个Mapper的namespace,然后再加上resultMap的id,如上。

1-2-3-2、强行使结果映射为多对一关系

如果数据是多对多的关系,使用association会强制转换为多对一关系(这种情况一般不存在),下面进行演示一下

1、首先去掉dept的主键索引
2、添加一条id重复的数据

image.png 3、查询数据库(原来的查询结果)

image.png 4、查询数据库(去掉唯一索引查询结果)
可以看到员工部门id为2的,都变成两条数据了 image.png 5、通过association查询的数据结果
可以看到会把多条数据强制变成一条,本来有运营部,但是这里没有查询出来。 image.png 6、通过排序再次查询
可以看到这次运营部出来了,但是销售部丢失了,因此association是强制多对一关系的。 image.png 7、association通过表的Id来进行排重的
如下,我们把e.* 改为e.name 只查询name,这样数据又重复出现了

使用association mybatis底层是根据id组织多对一关系的 image.png

1-2-4、使用association列名和resultMap映射不一致

如下图使用association使用resultMap的时候,查询中有两个Id,这时候就会出现映射不一致的问题。 image.png

1-2-4-1、使用加前缀的方式

如下图在查询的时候给dept表中的字段加上一个前缀,然后在association中添加columnPrefix属性再将加下面sql中的前缀,这样mybatis就知道这个加前缀的字段是哪个表的字段了。 image.png

1-2-4-1、使用原始映射的方式

image.png

1-2-5、小结

使用association的时候如果使用自定义映射,需要指定javaType属性,如果应用其他mapper则使用resultMap,并且值为namespace+resultMap的id。

如果重用resultMap, 则需要使用columnPrefix设置替换的前缀,另外sql字段加上要替换的前缀,需要注意的是,去掉前缀后的字段,需要和resultMap映射中column的字段一致。

1-3、使collection实现一对多关联查询

我们查询部门,然后关联它下面的员工,这样就形成了一对多的关联关系。

1-3-1、修改DeptMapper.xml

上过上面的叙述,我们知道在resultMap,可以集成其他的resultMap;并且使用其他Mapper的resultMap的时候可以通过namespace+resultMap的id进行关联 image.png

1-3-2、新建DeptEmpDTO

同样需要继承Dept的属性,和多对一不同的是,这个地方的Emp需要使用List来进行声明,因为查询出来事一个Dept对应多个Emp image.png

1-3-3、编写Mapper接口的方法

因为我们Mapper.xml中的sql语句查询的是所有Dept,因此这个方法的返回值需要是List image.png

1-3-4、测试

可以看到这样就实现了一对多的映射关系了。 image.png

1-3-5、collection的特点

collection基本和association差不多,只不过一个是一对多,一个是多对一。

1-3-5、实现一对多映射关系

实现一对多关系,需要注意的是collection中:
property:指定的是一对多中的“多”
ofType:需要指定多的别名或者完整限定名

1-3-6、同样可以使用其他Mapper的resultMap映射关系

和上面association实现方式一样。

1-3-6、列名映射关系不一致

需要注意的是collection和association一样,如果查询有多个同样的id,也会发送映射关系不一致的问题,解决方式和association一样,这里不再进行叙述。

1-3-7、实现一对多,ID列必查

collection和association一样,在实现映射的时候,主表的id列必查,否则mybatis就无法为我们进行对应关系的处理了如下:

image.png

1-4、小结

1、通过使用association和collection实现多对一和一对多映射关系的时候,都可以指定其他Mapper中的resultMap,但是必须使用namespace+resultMap的Id值。

2、使用映射关系的时候主表的id必须查询,否则mybatis就无法正确映射了。

3、如果遇到两个表有同样的字段,并且需要都查询的时候,可以使用原始resultMap的映射方式进行处理,或者通过columoPrefix去前缀的方式进行处理。