MyBatis关联查询之一对一查询
程序员文章站
2022-04-16 09:31:32
...
关联查询一对一查询是最基础的关联查询知识,何谓一对一。比如本文要讲到的例子,学生去图书馆借书的例子,有一个表叫做tb_user表示学生的信息,另一个表表示tb_book,那么假定每个人只能借一本书,那么两个表之间的关系就是一对一的,即一本书只能借给一个人,一个人只能借一本书。所以相对来说,一对一的关联查询,逻辑比较清晰,容易理解。我们接下来通过两种方法进行讲解一对一的关联查询。
1.示例简介
如下本文有如下两个表,tb_book表示被借出去书的情况,tb_user表示学生信息,现在需要查询借书者的相关信息。
如果用sql语句完成,则是如下语句:
select * from tb_user,tb_book where tb_book.user_id=tb_user.id
运行结果如下,正是需要的查询结果。接下来,介绍MyBatis中两种一对一关联查询的方法。2.方法一:通过构造新类
1.两个表对应有两个实体类:User类和Book类。查询结果是既有Book类中的属性值,又有User类中的属性值,并且查询结果是一个对象集合,如果使用泛型,那么泛型类型无法确定,那么就构造一个类,可以继承其中一个类,然后将另一个类需要的属性添加到这个新类中,那么这个新构造的类就是查询结果输出的类型。
首先是User类的代码,是一个典型的JavaBean
package com.mybatis.model.impl;
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+"]";
}
}
然后是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;
}
}
2.接着便是构造新类BookOrder类,这里让该类继承Book类,然后将需要的User类的属性添加进去。package com.mybatis.model.impl;
public class BookOrder extends Book {
//除了继承Book类的所有属性,还需要User中的name和sex属性
public String name;
public String sex;
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 String toString()
{
return "User [book_id="+book_id+",user_id="+user_id+",book_name="+book_name+",name="+name+",sex="+sex+"]";
}
}
3. 然后便是mapper代理文件BookOfUserMapper.xml,可以看出该代理文件内容比较简单,查询就是相当于普通的sql语句。<?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="getBookOfUser" resultType="com.mybatis.model.impl.BookOrder">
select tb_book.*,tb_user.name,tb_user.sex from tb_user,tb_book where tb_user.id=tb_book.user_id
</select>
</mapper>
4. 根据上述映射文件可以知道该代理文件对应的mapper接口是BookOfUserMapper接口。package com.mybatis.mapper;
import java.util.*;
import com.mybatis.model.impl.*;
public interface BookOfUserMapper {
public List<BookOrder> getBookOfUser();
//public List<Book1> getBookInfo();
}
5.将该mapper映射文件放入mybatis配置文件中 6.测试程序:
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();
//创建User对象
BookOfUserMapper bookOfUserMapper=session.getMapper(BookOfUserMapper.class);
List<BookOrder> list=bookOfUserMapper.getBookOfUser();
System.out.println(list);
}
}
7.运行测试程序,结果如下,正是需要的结果:3.方法二:通过映射文件
接下类讲述的是一种不需要增添新类的方法,即通过在mapper文件中进行操作。
1.首先假定最后输出的对象类型是Book1(区分上述的Book),但是在这个Book1类中需要添加User对象属性,相当于将两个类进行关联,以下是Book1类的代码:
package com.mybatis.model.impl;
import java.util.*;
public class Book1 {
public Integer book_id;
public Integer user_id;
public String book_name;
public User user;//添加User类型属性
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;
}
public User getUser()
{
return this.user;
}
public void setUser(User user)
{
this.user=user;
}
public String toString()
{
return "User [book_id="+book_id+",user_id="+user_id+",book_name="+book_name+",name="+user.getName()+",sex="+user.getSex()+"]";
}
}
2.然后就是User类:
package com.mybatis.model.impl;
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+"]";
}
}
3.然后便是mapper接口,定义相应的方法getBookInfo()。package com.mybatis.mapper;
import java.util.*;
import com.mybatis.model.impl.*;
public interface BookOfUserMapper {
//public List<BookOrder> getBookOfUser();
public List<Book1> getBookInfo();
}
4.然后便是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="getBookInfo" resultMap="bookOrder">
select tb_book.*,tb_user.name,tb_user.sex from tb_user,tb_book where tb_user.id=tb_book.user_id
</select>
<resultMap type="com.mybatis.model.impl.Book1" id="bookOrder">
<id property="user_id" column="user_id"/>
<result property="book_id" column="book_id"/>
<result property="book_name" column="book_name"/>
<association property="user" javaType="com.mybatis.model.impl.User">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sex" column="sex"/>
</association>
</resultMap>
</mapper>
从上述的mapper文件可以看出,该查询结果输出的是resultMap名为bookOrder,这里主要是为了与以下的resultMap的id相匹配,可以实现映射,并定义该resultMap输出类型是Book1类。首先先列出Book1类的元素,其中<id property="user_id" column="user_id"/>这里的id的property是查询中使用与外表关联的属性即user_id,其它属性则用<result....>列出。然后通过<association
property="user" javaType="com.mybatis.model.impl.User">来关联User类,即通过Book1类中的User类属性user来实现,这里的property:表示关联查询的结果存储在com.mybatis.model.impl.User的user属性中,javaType表示关联查询的结果类型为User类,相当于将User类的被查询的几个属性值存储在user属性作为Book1类的一个对象属性。
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<BookOrder> list=bookOfUserMapper.getBookOfUser();
System.out.println(list);
//通过mapper文件添加resultMap实现的查询结果
List<Book1> list1=bookOfUserMapper.getBookInfo();
System.out.println(list1);
}
}
6.运行程序结果如下,可以发现两种方法查询结果一致。3.两种方法比较
两种方法特点都非常明显,因此使用需要依情况而定。
1.方法一优点就是mapper映射文件简洁,但是需要添加新类,那么无疑添加了系统的复杂度。
2.方法二就是不用添加许多类,但是mapper映射文件变得十分复杂,如果查询多而且复杂,那么文件内容会十分庞大。
如果需要源代码,请点击mybatisdemo下载。