二.MyBatis多表查询的不同方式
一对多查询
1.首先建立实体对象,国家和州长,Country,Minister
国家和州是一对多的关系,一个国家对应多个州长,所以国家的对象中应该有一个属性来描述州长们,用Set集合是防止有重复
每一个州长也都得知道自己是属于哪一个国家的,所以州长类有一个描述自己是哪个国家的属性 country
写实体类时,属性不要用驼峰标志,可能会出错(现在我也不知道会出什么错,先记录着)
州长和国家的toString方法不能互相包括对方,不然会无限递归调用,只能有一方可以打印另一方的信息
2.然后建立数据库表
country表:
minister表:
在建数据库表时,如果把国家和州长的关系放大国家表中表示,则会产生大量冗余数据,是及其不合理的设计,放到州长表中是正确的,得出结论,一对多关系中,外键建立在多的一方上。
在封装对象的时候,作为一的,应该持有集合引用(包含多的的集合),作为多的,应该持有一的对象引用
3.定义接口
定义接口的目的是让myBatis用动态代理帮我们创建实现类,不用再手动创建。
(myBatis实现动态代理的要求:1.在接口中定义的方法和映射文件中的id相同,2.映射文件的namespace是接口的全限定性类名)
4.写mapper映射文件
模拟需求:要求根据ID查询出国家以及国家下的所有州长的信息
根据需求可知,需要多表查询才可以实现,第一种查询方法如下所示
查询出来的结果是一个Country对象,但是Country对象中含有一个集合属性,直接写resultType=”Country”是无法实现把查询出的数据封装成Country对象的,所以用到了resultMap标签
图中的两条红线为对应关系
5.测试
结果:
DEBUG ==> Preparing: select cname,cid,mid,mname from country,minister where cid = countryId and cid = ?
DEBUG ==> Parameters: 2(Integer)
DEBUG <== Total: 2
Country [cid=2, cname=england, ministers=[Minister [mid=4, mname=ddd, country=null], Minister [mid=5, mname=eee, country=null]]]
还有一种查询方法
把两条sql语句分开写,这种方式比较常用,因为它可以使用缓存机制,如下图
多对一查询
需求:根据id查询出州长的信息(州长对象中持有对国家的引用)
使用在Minister对象中封装Country属性
不使用Country对象中的那个集合属性
定义接口
编写映射文件
测试:
测试结果
mid为什么是null呢?翻看配置文件后发现,mid配置错了
改正后测试结果为:
查询成功,下面使用多表单独查询实现
更改mapper文件
测试结果:
查询成功
一次把需要的信息都查出来的用多标签直接赋值,需要多次查询的要查多次的需要使用select属性如下图
自关联查询
模拟一个环境:一个新闻栏目,有很多栏目,存在父子关系如下:
娱乐新闻 ---> 港台明星
---> 内地影视
体育新闻 ---> NBA ---> 火箭
---> 湖人
---> CBA ---> 北京金隅
---> 浙江广厦
---> 青岛双星
需求:给定一个栏目查出该栏目下的所有栏目(不包括自身)
解决:
创建表
定义新闻栏目实体类
定义接口
映射文件
先根据传入的父id进行查询,查询出来的结果由resultMap解析,解析到集合的时候需要查询当前栏目有没有子栏目,所以再次调用了查询,触发递归查询,一直到没有子栏目为止。
测试:
测试结果:
又提出了需求:给定一个栏目查出该栏目下的所有栏目(包括自身)
只需要修改映射文件,如下图: