MyBatis學習筆記:一對一和一對多關聯表查詢
在前面的兩篇博文的例子中,都是簡單的實體類,都不存在包括其他實體類的引用。
例如:班級類Class
public class Classes {
private int id;
private String name;
//getter setter
}
這種情況下,如果你想根據班級的id來查班級的信息,則在sql映射文件ClassMapper.xml中寫入如下的代碼:
<select id="queryById" parameterType="int" resultType="com.wrh.entity.Classes">
SELECT * FROM class WHERE s_id=#{id}
</select>
並在相應的位置寫類似於下面的代碼就可以查出班級的信息了。
@Test
public void queryById(){
sqlSession = MybatisUtil.getSqlSession();
int id = 1;
try{
Classes classes = sqlSession.selectOne("mapper.ClassMapper.queryById",id);
System.out.println(classes);
}catch (Exception e){
e.printStackTrace();
}finally {
MybatisUtil.closeSession(sqlSession);
}
}
但是,一般情況下,一個班級都有一個班主任,是吧,如果現在實體類Classes有Teacher這個屬性,則依靠上面的sql就不能查詢出班級的信息(包括老師)了。
還有,一般情況下,一個班級有多個學生,是吧,如果現在實體類Classes有List這個屬性,則就更復雜了
public class Classes {
private int id;
private String name;
private Teahcer teacher;
//getter setter
}
那麼,具體該怎麼做呢?這就是本篇博文要介紹的一對一和一對多關聯表查詢可以解決這個問題。
一對一關聯表查詢
1、數據庫表的準備:class、teacher
其中class包括三個字段:c_id、c_name、teacher_id
teacher包括兩個字段:t_id、t_name
具體如下:
2、class表和teacher對應的實體類:Classes、Teacher
Teacher.java
package com.wrh.entity;
/**
* @Author:wojiushimogui
* @Description:
* @Date:Created by 下午2:50 on 2017/9/3.
*/
public class Teacher {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Teacher{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
Classes.java
package com.wrh.entity;
/**
* @Author:wojiushimogui
* @Description:
* @Date:Created by 下午2:51 on 2017/9/3.
*/
public class Classes {
private int id;
private String name;
/**
* class表中有一個teacher_id字段,所以在Classes類中定義一個teacher屬性,
* 用於維護teacher和class之間的一對一關係,通過這個teacher屬性就可以知道這個班級是由哪個老師負責的
*/
private Teacher teacher;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
@Override
public String toString() {
return "Classes{" +
"id=" + id +
", name='" + name + '\'' +
", teacher=" + teacher +
'}';
}
}
3、sql映射文件classMapper.xml
具體內容如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.ClassMapper">
<!--
假設我們要幹這樣一件事情:根據class id查的 該班級的信息(包括teacher的信息)。
-->
<!-- 第一種方式:-->
<select id="queryClassById" parameterType="int" resultMap="classResultMap">
SELECT * FROM class c,teacher t where c.teacher_id = t.t_id AND c_id =#{id}
</select>
<resultMap id="classResultMap" type="com.wrh.entity.Classes">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" javaType="com.wrh.entity.Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
</association>
</resultMap>
<!--第二種方式:嵌套查詢
select * from class where c_id = #{id};
select * from teacher where t_id = 1;//其中 1爲是上一個查詢得到的teacher_id的值
-->
<select id="queryClassById2" parameterType="int" resultMap="classResultMap2">
SELECT * FROM class WHERE c_id = #{id}
</select>
<resultMap id="classResultMap2" type="com.wrh.entity.Classes">
<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="com.wrh.entity.Teacher">
SELECT t_id id,t_name name FROM teacher WHERE t_id = #{id}
</select>
</mapper>
4、註冊:將ClassMapper.xml文件註冊在mybatis-config.xml配置文件中
<mappers>
<mapper resource="mapper/ClassMapper.xml"/>
</mappers>
5、測試
public class ClassTest {
SqlSession sqlSession ;
@Test
public void queryClassById(){
sqlSession = MybatisUtil.getSqlSession();
int id = 2;
try{
Classes classes = sqlSession.selectOne("mapper.ClassMapper.queryClassById",id);
System.out.println(classes);//Classes{id=2, name='heihei', teacher=Teacher{id=1, name='wojiushimogui'}}
}catch (Exception e){
e.printStackTrace();
}finally {
MybatisUtil.closeSession(sqlSession);
}
}
@Test
public void queryClassById2(){
sqlSession = MybatisUtil.getSqlSession();
int id = 2;
try{
Classes classes = sqlSession.selectOne("mapper.ClassMapper.queryClassById2",id);
System.out.println(classes);//Classes{id=2, name='heihei', teacher=Teacher{id=1, name='wojiushimogui'}}
}catch (Exception e){
e.printStackTrace();
}finally {
MybatisUtil.closeSession(sqlSession);
}
}
}
一對多關聯表查詢
在一對一的基礎上我們做如下的修改即可。
1、添加Student實體類
Student實體類
package com.wrh.entity;
/**
* @Author:wojiushimogui
* @Description:
* @Date:Created by 下午1:19 on 2017/9/3.
*/
public class Student {
private int id;
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
此實體對應的表結構和內容如下:
2、修改Classes類
Classes實體類
package com.wrh.entity;
import java.util.List;
/**
* @Author:wojiushimogui
* @Description:
* @Date:Created by 下午2:51 on 2017/9/3.
*/
public class Classes {
private int id;
private String name;
/**
* class表中有一個teacher_id字段,所以在Classes類中定義一個teacher屬性,
* 用於維護teacher和class之間的一對一關係,通過這個teacher屬性就可以知道這個班級是由哪個老師負責的
*/
private Teacher teacher;
//一對多的關係
private List<Student> studentList;
public List<Student> getStudentList() {
return studentList;
}
public void setStudentList(List<Student> studentList) {
this.studentList = studentList;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
@Override
public String toString() {
return "Classes{" +
"id=" + id +
", name='" + name + '\'' +
", teacher=" + teacher +
", studentList=" + studentList +
'}';
}
}
3、sql映射文件ClassMapperOne2Many.xml
具體內容如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.ClassMapperOne2Many">
<!--
假設我們要幹這樣一件事情:根據class id查的 該班級的信息(包括teacher、student的信息)。
-->
<!-- 第一種方式:-->
<select id="queryClassById" parameterType="int" resultMap="classResultMap">
SELECT * FROM class c,teacher t ,student s where c.teacher_id = t.t_id and c.c_id = s.class_id AND c_id =#{id}
</select>
<resultMap id="classResultMap" type="com.wrh.entity.Classes">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" javaType="com.wrh.entity.Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
</association>
<collection property="studentList" ofType="com.wrh.entity.Student">
<id property="id" column="s_id"/>
<result property="name" column="s_name"/>
</collection>
</resultMap>
<!--第二種方式:嵌套查詢
select * from class where c_id = #{id};
select * from teacher where t_id = 1;//其中 1爲是上一個查詢得到的teacher_id的值
select * from student where class_id = 1;//其中 1爲是上一個查詢得到的c_id的值
-->
<select id="queryClassById2" parameterType="int" resultMap="classResultMap2">
SELECT * FROM class WHERE c_id = #{id}
</select>
<resultMap id="classResultMap2" type="com.wrh.entity.Classes">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" column="teacher_id" select="getTeacher"/>
<collection property="studentList" ofType="com.wrh.entity.Student" column="c_id" select="getStudent"/>
</resultMap>
<select id="getTeacher" parameterType="int" resultType="com.wrh.entity.Teacher">
SELECT t_id id,t_name name FROM teacher WHERE t_id = #{id}
</select>
<select id="getStudent" parameterType="int" resultType="com.wrh.entity.Student">
SELECT s_id id,s_name name,s_age age from student where class_id = #{id}
</select>
</mapper>
4、將sql映射文件註冊到mybatis-config.xml文件中
<mappers>
<mapper resource="mapper/ClassMapperOne2Many.xml"/>
</mappers>
5、測試
public class ClassTest {
SqlSession sqlSession ;
@Test
public void queryClassById(){
sqlSession = MybatisUtil.getSqlSession();
int id = 2;
try{
// Classes classes = sqlSession.selectOne("mapper.ClassMapper.queryClassById",id);
Classes classes = sqlSession.selectOne("mapper.ClassMapperOne2Many.queryClassById",id);
System.out.println(classes);//Classes{id=2, name='heihei', teacher=Teacher{id=1, name='wojiushimogui'}}
}catch (Exception e){
e.printStackTrace();
}finally {
MybatisUtil.closeSession(sqlSession);
}
}
@Test
public void queryClassById2(){
sqlSession = MybatisUtil.getSqlSession();
int id = 2;
try{
// Classes classes = sqlSession.selectOne("mapper.ClassMapper.queryClassById2",id);
Classes classes = sqlSession.selectOne("mapper.ClassMapperOne2Many.queryClassById2",id);
System.out.println(classes);//Classes{id=2, name='heihei', teacher=Teacher{id=1, name='wojiushimogui'}}
}catch (Exception e){
e.printStackTrace();
}finally {
MybatisUtil.closeSession(sqlSession);
}
}
}
測試結果符合預期。
在測試過程中,遇到了如下的問題:
產生的原因:ClassMapperOne2Many.xml文件中將 中的namespace的內容寫成了mapper.ClassMapper。所以要細心。
總結
MyBatis中是使用association標籤來解決一對一的關聯查詢,
形式爲:
<select id="queryClassById" parameterType="int" resultMap="classResultMap">
SELECT * FROM class c,teacher t where c.teacher_id = t.t_id AND c_id =#{id}
</select>
<resultMap id="classResultMap" type="com.wrh.entity.Classes">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" javaType="com.wrh.entity.Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
</association>
</resultMap>
或者是
<select id="queryClassById2" parameterType="int" resultMap="classResultMap2">
SELECT * FROM class WHERE c_id = #{id}
</select>
<resultMap id="classResultMap2" type="com.wrh.entity.Classes">
<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="com.wrh.entity.Teacher">
SELECT t_id id,t_name name FROM teacher WHERE t_id = #{id}
</select>
其中,association標籤可用的屬性如下:
property:對象屬性的名稱
javaType:對象屬性的類型
column:所對應的外鍵字段名稱
select:使用另一個查詢封裝的結果
而MyBatis中是使用collection標籤來解決一對多的關聯查詢, 形式如下:
<select id="queryClassById" parameterType="int" resultMap="classResultMap">
SELECT * FROM class c,teacher t ,student s where c.teacher_id = t.t_id and c.c_id = s.class_id AND c_id =#{id}
</select>
<resultMap id="classResultMap" type="com.wrh.entity.Classes">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" javaType="com.wrh.entity.Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
</association>
<collection property="studentList" ofType="com.wrh.entity.Student">
<id property="id" column="s_id"/>
<result property="name" column="s_name"/>
</collection>
</resultMap>
或者是
<select id="queryClassById2" parameterType="int" resultMap="classResultMap2">
SELECT * FROM class WHERE c_id = #{id}
</select>
<resultMap id="classResultMap2" type="com.wrh.entity.Classes">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" column="teacher_id" select="getTeacher"/>
<collection property="studentList" ofType="com.wrh.entity.Student" column="c_id" select="getStudent"/>
</resultMap>
<select id="getTeacher" parameterType="int" resultType="com.wrh.entity.Teacher">
SELECT t_id id,t_name name FROM teacher WHERE t_id = #{id}
</select>
<select id="getStudent" parameterType="int" resultType="com.wrh.entity.Student">
SELECT s_id id,s_name name,s_age age from student where class_id = #{id}
</select>