6 mybatis 关联关系查询

xiaoxiao2025-11-15  8

关联关系

对学习课程的总结:

当查询内容涉及到具有关联关系的多个表时,就需要使用关联查询。根据表与表间的关联关系的不同,关联查询分为四种:

一对一关联查询一对多关联查询多对一关联查询多对多关联查询

一、一对多关联查询

一对多关联查询是指,在查询一方对象的时候,同时将其所关联的多方对象也都查询出来。 建立实体类: minister部长、大臣 country国家

public class Minister { private Integer mid; private String mname; //getter()/setter() } public class Country { private Integer cid; private String cname; //关联属性 private Set<Minister> ministers; //getter()/setter() }

方式一:通过多表连接的方式

dao层接口:

Country selectCountryById(int id);

mapper配置

<mapper namespace="com.chen.dao.ICountryDao"> <resultMap id="countryMapper" type="Country"> <id column="cid" property="cid"/> <result column="cname" property="cname"/> <collection property="ministers" ofType="Minister"> <id column="mid" property="mid"/> <result column="mname" property="mname"/> </collection> </resultMap> <select id="selectCountryById" resultMap="countryMapper"> SELECT cid, cname, mid, mname FROM country, minister WHERE countryId = cid AND cid = #{id} </select> </mapper>

测试

@Test public void testSelectCountryById(){ SqlSession sqlSession = null; try{ sqlSession = MyBatisUtils.getSqlSession(); ICountryDao mapper = sqlSession.getMapper(ICountryDao.class); Country country = mapper.selectCountryById(2); System.out.println(country); }finally{ if(sqlSession != null){ sqlSession.close(); } } }

方式二:通过多表单独方式实现

mapper配置

<select id="selectMinisterByCountry" resultType="Minister"> SELECT mid, mname FROM minister WHERE countryId = #{column} </select> <resultMap id="countryMapper" type="Country"> <id column="cid" property="cid"/> <result column="cname" property="cname"/> <collection property="ministers" ofType="Minister" select="selectMinisterByCountry" column="cid"/> </resultMap> <select id="selectCountryById" resultMap="countryMapper"> SELECT cid, cname FROM country WHERE cid = #{cid} </select>

dao层接口与测试同上


二、多对一的关联查询

查询多方对象的时候,同时将其所关联的一方对象也查询出来

由于在查询多方对象时也是一个一个查询,所以多对一关联查询,其实就是一对一关联查询,即一对一关联查询的实现方式与多对一的实现方式是相同的

方式一:多表连接查询

dao层接口

Minister selectMinisterById(int mid);

mapper配置

<resultMap id="ministerMapper" type="Minister"> <id column="mid" property="mid"/> <result column="mname" property="mname"/> <association property="country" javaType="Country"> <id column="cid" property="cid"/> <result column="cname" property="cname"/> </association> </resultMap> <select id="selectMinisterById" resultMap="ministerMapper"> SELECT mid, mname, cid, cname FROM minister, country WHERE countryId = cid AND mid = #{mid} </select>

测试

public class Many_2_One { private IMinisterDao mapper; private SqlSession sqlSession; @Before public void before() { sqlSession = MyBatisUtils.getSqlSession(); mapper = sqlSession.getMapper(IMinisterDao.class); } @After public void after() { if (sqlSession != null) { sqlSession.close(); } } @Test public void test() { Minister minister = mapper.selectMinisterById(2); System.out.println(minister); } }

方式二: 多表单独方式查询

mapper配置

<select id="selectCountryByMinister" resultType="Country"> SELECT cid, cname FROM country WHERE cid = #{xxx} </select> <resultMap id="ministerMapper" type="Minister"> <id column="mid" property="mid"/> <result column="mname" property="mname"/> <association property="country" javaType="Country" select="selectCountryByMinister" column="countryId"> </association> </resultMap> <select id="selectMinisterById" resultMap="ministerMapper"> SELECT mid, mname, countryId FROM minister WHERE mid = #{mid} </select>

三、自关联查询

自关联查询,自己既是一方,又是多方,是1:n或n:1的变型。

例如,对于新闻栏目NewsColumn,可以充当一方,即父栏目,也可以充当多方,即子栏目,而反应到DB表中,只有一张表,这张表中具有一个外键,用于表示该栏目的父栏目。一级栏目没有父栏目,所有可以将其外键值设为0,而子栏目则具有外键值。

为了便于理解,将自关联分为两种情况来讲解,一种是当作1:n讲解,即当前类作为一方,其包含多方的集合域属性。一种是当作n:1讲解,即当前类作为多方,其包含一方的域属性。

下面以新闻栏目为例进行讲解。由于column是DBMS中的关键字,为了避免误解,将新闻栏目实体类定义为NewsLabel。

数据库表 其中pid为parent id,即其父id

idnamepid1娱乐新闻02体育新闻03NBA24CBA25火箭36湖人37北京金隅48浙江广厦49青岛双星410港台明星111内地影视1

以一对多方式处理

(1)查询指定栏目的所有子孙栏目 实体类

//新闻栏目:当前的新闻栏目被看作是一方,即父栏目 public class NewsLabel { private Integer id; private String name; //栏目名称 private Set<NewsLabel> children; //此处省略getter()/setter()/toString() }

dao接口

List<NewsLabel> selectChildrenByParent(int pid);

mapper配置

<mapper namespace="com.chen.dao.INewsLabelDao"> <!-- 递归调用 --> <resultMap id="newsLabelMapper" type="NewsLabel"> <id column="id" property="id"/> <result column="name" property="name"/> <collection property="children" ofType="NewsLabel" select="selectChildrenByParent" column="id"/> </resultMap> <select id="selectChildrenByParent" resultMap="newsLabelMapper"> SELECT id, name FROM newslabel WHERE pid = #{pid} </select> </mapper>

测试

public class NewsLabelTest { private INewsLabelDao mapper; SqlSession sqlSession; @Before public void before() { sqlSession = MyBatisUtils.getSqlSession(); mapper = sqlSession.getMapper(INewsLabelDao.class); } @After public void after() { if (sqlSession != null) { sqlSession.close(); } } @Test public void testNewsLabel() { List<NewsLabel> children = mapper.selectChildrenByParent(2); for (NewsLabel newslabel : children) { System.out.println(newslabel); } } }

测试结果

NewsLabel{id=3, name='NBA', children=[NewsLabel{id=5, name='火箭', children=[]}, NewsLabel{id=6, name='湖人', children=[]}]} NewsLabel{id=4, name='CBA', children=[NewsLabel{id=8, name='浙江广厦', children=[]}, NewsLabel{id=9, name='青岛双星', children=[]}, NewsLabel{id=7, name='北京金隅', children=[]}]}

(2)查询指定栏目及其所有子孙栏目

dao接口

NewsLabel selectNewsLabelById(int id);

mapper配置

<!-- 递归调用,查询子栏目 --> <select id="selectNewsLabelByPid" resultMap="newsLabelMapper2"> SELECT id, name FROM newslabel WHERE pid = #{column} </select> <resultMap id="newsLabelMapper2" type="NewsLabel"> <id column="id" property="id"/> <result column="name" property="name"/> <collection property="children" ofType="NewsLabel" select="selectNewsLabelByPid" column="id"/> </resultMap> <!-- 根据id查询栏目,只查了一次 --> <select id="selectNewsLabelById" resultMap="newsLabelMapper2"> SELECT id, name FROM newslabel WHERE id = #{id} </select>

测试

@Test public void testSelectNewsLabelById() { NewsLabel newsLabel = mapper.selectNewsLabelById(2); System.out.println(newsLabel); }

结果

NewsLabel{id=2, name='体育新闻', children=[ NewsLabel{id=4, name='CBA', children=[NewsLabel{id=9, name='青岛双星', children=[]}, NewsLabel{id=7, name='北京金隅', children=[]}, NewsLabel{id=8, name='浙江广厦', children=[]}]}, NewsLabel{id=3, name='NBA', children=[NewsLabel{id=6, name='湖人', children=[]}, NewsLabel{id=5, name='火箭', children=[]}]}]}

以多对一方式处理

以多对一方式处理,即多方可以看到一方。该处理方式的应用场景,例如在网页上显示当前页面的站内位置。 需求:查询当前栏目及其所有父辈栏目 实体类

//新闻栏目:当前的新闻栏目被看作是多方,即子栏目 public class NewsLabel2 { private Integer id; private String name; //栏目名称 private NewsLabel2 parent; //此处省略getter()/setter()/toString() }

dao接口

NewsLabel2 selectNewsLabelById2(int id);

mapper配置

<resultMap id="newLabelMapper3" type="NewsLabel2"> <id column="id" property="id"/> <result column="name" property="name"/> <association property="parent" javaType="NewsLabel2" select="selectNewsLabelById2" column="pid"/> </resultMap> <select id="selectNewsLabelById2" resultMap="newLabelMapper3"> SELECT id, name, pid FROM newslabel WHERE id = #{id} </select>

测试

@Test public void testSelectNewsLabelById2() { //查询id为3的栏目,及其所有父栏目 NewsLabel2 newsLabel2 = mapper.selectNewsLabelById2(3); System.out.println(newsLabel2); }

结果

NewsLabel2{id=3, name='NBA', parent=NewsLabel2{id=2, name='体育新闻', parent=null}}

实际开发中NewsLabel中自关联实体类应如下定义,上面的方式,是为了更好的理解自关联,所以分开进行讲解

public class NewsLabel { private Integer id; private String name; //栏目名称 private NewsLabel parent; //父栏目 private Set<NewsLabel> children; //子栏目 //此处省略getter()/setter()/toString() }

多对多关联查询

什么是多对多关联关系?一个学生可以选择多门课程,而一门课程可由多个学生选。这就是典型的多对多关系。所以,所谓多对多关系,其实就是由两个互反的一对多关系组成。

一般情况下,多对多关系都会通过一个中间表来建立,例如选课表

注意:students2和course是一方,中间表middle是多方!!!

数据库表 students2:

sidsname1张三2李四3王五

course:

cidcname1JavaSE2JavaEE3Android

中间表:

实体类

在定义双向关联(双方均可看到对方的关联关系)的实体的toString()方法时,只让一方的toString()方法中可以输出对方,不要让双方均可输出对方,否则将会出现输出时的递归现象,程序报错

public class Student2 { private Integer sid; private String sname; private Set<Course> courses; //省略getter()/setter()/toString() } public class Course { private Integer cid; private String cname; private Set<Student2> student2s; //省略getter()/setter()/toString() }

dao接口

Student2 selectStudentById(int sid);

mapper配置

<mapper namespace="com.chen.dao.IStudent2Dao"> <resultMap id="studentMapper" type="Student2"> <id column="sid" property="sid"/> <result column="sname" property="sname"/> <collection property="courses" ofType="Course"> <id column="cid" property="cid"/> <result column="cname" property="cname"/> </collection> </resultMap> <select id="selectStudentById" resultMap="studentMapper"> SELECT sid, sname, cid, cname FROM student2, middle, course WHERE sid = studentId AND cid = courseId and sid=#{sid} </select> </mapper>

测试

public class Many2ManyTest { private IStudent2Dao mapper ; SqlSession sqlSession; @Before public void before() { sqlSession = MyBatisUtils.getSqlSession(); mapper = sqlSession.getMapper(IStudent2Dao.class); } @After public void after() { if (sqlSession != null) { sqlSession.close(); } } @Test public void testNewsLabel() { Student2 student2 = mapper.selectStudentById(1); System.out.println(student2); } }

结果

Student2{sid=1, sname='张三', courses=[Course{cid=2, cname='JavaEE'}, Course{cid=1, cname='JavaSE'}]}
转载请注明原文地址: https://www.6miu.com/read-5039699.html

最新回复(0)