MyBatis关联查询之一对多查询

时间:2023-02-03 11:56:22

        一对多的关系就是指第一个表中的单个行可以与第二个表中的一个或多个行相关,但第二个表中的一个行只可以与第一个表中的一个行相关。就如同借书,假设某个人一年内只借了一本书,并且借了好几次,那么这个人就会对应着好多条借书记录,但是每条借书记录只会对应着一个人,因为一本书不可能同时借给两个人,这就是一对多的关系。本文还是举借书的例子,在一对一查询基础上进行改进的,如有需要可以两篇文章一起看。

1.涉及的数据表及其po类

  本文涉及的数据表总共三个:tb_time,tb_user,tb_book。
MyBatis关联查询之一对多查询MyBatis关联查询之一对多查询MyBatis关联查询之一对多查询
其对应的三个po类如下所示:
Time类:
package com.mybatis.model.impl;

public class Time {
public String book_id;
public String fromtime;
public String totime;
public Integer totaltime;
public Integer user_id;

public void setBook_id(String book_id)
{
this.book_id=book_id;
}
public String getBook_id()
{
return this.book_id;
}

public void setFromTime(String fromtime)
{
this.fromtime=fromtime;
}
public String getFromTime()
{
return this.fromtime;
}

public void setToTime(String totime)
{
this.totime=totime;
}
public String getToTime()
{
return this.totime;
}

public void setTotalTime(Integer totaltime)
{
this.totaltime=totaltime;
}
public Integer getTotalTime()
{
return this.totaltime;
}
public Integer getUser_id()
{
return this.user_id;
}

public void setUser_id(Integer user_id)
{
this.user_id=user_id;
}
public String toString()
{
return "Time [user_id="+user_id+",fromtime="+fromtime+",totime="+totime+",totaltime="+totaltime+"]";
}

}
Book类:
package com.mybatis.model.impl;

public class Book {
public Integer book_id;
public Integer user_id;
public String book_name;

public Integer getBook_id()
{
return this.book_id;
}

public void setBook_id(Integer book_id)
{
this.book_id=book_id;
}

public Integer getUser_id()
{
return this.user_id;
}

public void setUser_id(Integer user_id)
{
this.user_id=user_id;
}

public String getBook_name()
{
return this.book_name;
}

public void setBook_name(String book_name)
{
this.book_name=book_name;
}

}
User类:

import java.io.Serializable;
public class User implements Serializable {
private Integer id;
private String name;
private String sex;
private Integer age;
public User()
{
}
public User(String name,String sex,Integer age)
{
this.name=name;
this.sex=sex;
this.age=age;
}
public Integer getId()
{
return this.id;
}
public void setId(Integer id)
{
this.id=id;
}

public String getName()
{
return this.name;
}
public void setName(String name)
{
this.name=name;
}

public String getSex()
{
return this.sex;
}
public void setSex(String sex)
{
this.sex=sex;
}

public Integer getAge()
{
return this.age;
}
public void setAge(Integer age)
{
this.age=age;
}
public String toString()
{
return "User [id="+id+",name="+name+",sex="+sex+",age"+age+"]";
}
}

2.构造输出对象类

        本文的目的是查询出每个人的借书记录,那么很明显人与书是关联的,并且每个人都有一个借书记录,用集合存储,那么就令输出对象类型为改进的user类,暂令User1类,其中需要添加一个Book对象属性,以及List<Time>属性,具体如下所示:
package com.mybatis.model.impl;
import java.util.*;
import java.io.Serializable;
public class User1 {
public Integer id;
public String name;
public String sex;
public Integer age;
public List<Time> times;//借书时间记录,用集合表示
public Book book;//书信息对象

public Integer getId()
{
return this.id;
}
public void setId(Integer id)
{
this.id=id;
}

public String getName()
{
return this.name;
}
public void setName(String name)
{
this.name=name;
}

public String getSex()
{
return this.sex;
}
public void setSex(String sex)
{
this.sex=sex;
}

public Integer getAge()
{
return this.age;
}
public void setAge(Integer age)
{
this.age=age;
}
public List<Time> getTime()
{
return this.times;
}
public void setTime(List<Time> times)
{
this.times=times;
}
public String toString()
{
return "Book [book_id="+book.book_id+",user_id="+id+",book_name="+book.book_name+",name="+name+",sex="+sex+",times="+times+"]";
}

}


3.mapper接口及其对应mapper文件

mapper接口:
package com.mybatis.mapper;
import java.util.*;
import com.mybatis.model.impl.*;
public interface BookOfUserMapper {
//public List<BookOrder> getBookOfUser();
//public List<Book1> getBookInfo();
//public List<Book2> getBookAllInfo();
public List<User1> getInfo();


}
mapper文件:
<?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="com.mybatis.mapper.BookOfUserMapper">

<select id="getInfo" resultMap="user1">
select tb_book.*,
tb_user.name,tb_user.sex,
tb_time.fromtime,tb_time.totime,tb_time.totaltime
from tb_user,tb_book,tb_time
where tb_user.id=tb_book.user_id
and tb_book.book_id=tb_time.book_id
</select>
<resultMap type="com.mybatis.model.impl.User1" id="user1">
<id property="id" column="user_id"/>
<result property="name" column="name"/>
<result property="sex" column="sex"/>
<association property="book" javaType="com.mybatis.model.impl.Book">
<id property="user_id" column="user_id"/>
<result property="book_name" column="book_name"/>
<result property="book_id" column="book_id"/>
</association>
<collection property="times" ofType="com.mybatis.model.impl.Time">
<id property="fromtime" column="fromtime"/>
<result property="fromtime" column="fromtime"/>
<result property="totime" column="totime"/>
<result property="totaltime" column="totaltime"/>
</collection>
</resultMap>

</mapper>
        观察上述mapper文件:
1.首先使用了resultMap属性,这就是将查询最终结果映射成集合,并且对象类型为User1类型,并且property是指相应类中的属性名,column则是数据表的列名,值得注意的是id元素内的属性具有标识唯一性,即不重复的。另外<result..>中的property和column意义同上,只不过不要求标识唯一性。
2.<association...property=  javaType=>中property则是输出类中的对象属性名,javaType则是对应的类。<association/>中的那些元素意义与之前相同。
3.<collection  property=""  ofType="">property指的是在输出类中对应的属性名,即集合名,ofType即集合元素对应的类。其余元素意义同上。

4.将mapper加载到mybatis配置文件中

如下是mybatis配置文件,本文对应的mapper文件加载进该配置文件中,如下图深色部分。
MyBatis关联查询之一对多查询

5.测试程序并测试

        测试程序:
package com.mybatis.test;
import java.util.*;
import java.io.InputStream;
import org.apache.ibatis.io.*;
import org.apache.ibatis.session.*;

import com.mybatis.mapper.*;
import com.mybatis.model.impl.*;;

public class QueryTest {

public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
// TODO Auto-generated method stub
//读取MyBatis配置文件
InputStream inputStream=Resources.getResourceAsStream("mybatis-config.xml");
//初始化mybatis,创建SqlSessionFactory类的实例。
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
//创建Session实例
SqlSession session=sqlSessionFactory.openSession();

BookOfUserMapper bookOfUserMapper=session.getMapper(BookOfUserMapper.class);

List<User1> list3=bookOfUserMapper.getInfo();
System.out.println(list3);
}

}
 运行程序得到如下结果:
DEBUG [main] - <==      Total: 6
[Book [book_id=1002,user_id=2005,book_name=Java编程思想,name=Tom,sex=男,times=[Time [fromtime=20150302,totime=20150402,totaltime=30], Time [fromtime=20150602,totime=20150702,totaltime=30], Time [fromtime=20150910,totime=20150930,totaltime=20]]], Book [book_id=1001,user_id=2001,book_name=西游记,name=Carson,sex=男,times=[Time [fromtime=20151103,totime=20151126,totaltime=23], Time [fromtime=20151224,totime=20160123,totaltime=30]]], Book [book_id=1003,user_id=2008,book_name=HeadFirst设计模式,name=Thl,sex=女,times=[Time [fromtime=20160321,totime=20160423,totaltime=30]]]]
以下是在数据库中进行的查询操作,结果与上述通过Mybatis进行操作的结果一致。

MyBatis关联查询之一对多查询
        通过上述实例,关于一对多查询有几点需要注意的:
1.一对多查询的概念
2.构造输出类的思想,即在现有类中添加关联属性
3.mapper文件中resultMap、association、collection元素的使用。