MyBatis关联 查询之多对多查询
一对一查询、 一对多查询两篇文章分别讲了关联查询中的一对一查询和一对多查询,假设有两个表A和B,那么一对一就是A表中的每行记录仅对应B表的一条记录,同理B表的一条记录只对应A表的一条记录;一对多则是A表中的单行可以与B表中的一个或多个行相关,但B表中的一个行只可以与A表中的一个行相关;那么多对多则是A表中的单行可以与B表中的一个或多个行相关,B表中的单行可以与A表中的一个或多个行相关。本文通过举例子的方式进行介绍多对多的情况。
1.案例准备
本文的例子采用人借书(一对多),书分种类(多对多),种类对应种类名字(一对一)的复杂关系来讲解多对多的关系。涉及的表分别命名为user、book、booktype、type。首先在MySQL上进行建表。
1.建立第一个表示借书者的表,即user,代码即数据如下图所示:
2.建立book表:
3.建立booktype表:
4.建立type表:
5.根据需要实现的要求,进行sql查询,代码如下:
- select user.id user_id,user.name user_name,book.id book_id,book.name book_name,booktype.type typeid,type.name type_name
- from book,booktype,user,type
- where user.id=book.user_id
- and book.id=booktype.book_id
- and booktype.type=type.id;
查询结果如下图所示:
2.使用MyBatis框架关联查询
1.根据数据表以及表之间的关联建立相应的实体类
1.User1类,每一个user可以借多本书,因此在User1类中添加集合属性List<Book1> book,其余属性与数据表对应即可。
- package com.mybatis.model.impl;
- import java.util.*;
- import java.io.Serializable;
- public class User1 {
- public Integer id;
- public String name;
- public List<Book1> 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 List<Book1> getBook()
- {
- return this.book;
- }
- public void setBook(List<Book1> book)
- {
- this.book=book;
- }
- public String toString()
- {
- return "User [user_id="+id+",name="+name+",book="+book+"]";
- }
- }
2.建立一个Book1类,这里每一本书可以有多个种类,添加集合属性List<BookType>bookType来表示两者的关联。
- package com.mybatis.model.impl;
- import java.util.*;
- public class Book1 {
- public Integer id;
- public String user_id;
- public String name;
- public List<BookType> bookType;//书划分种类的集合,一本书可以被划分为好几种类,
- public Integer getBook_id()
- {
- return this.id;
- }
- public void setBook_id(Integer id)
- {
- this.id=id;
- }
- public String getUser_id()
- {
- return this.user_id;
- }
- public void setUser_id(String user_id)
- {
- this.user_id=user_id;
- }
- public String getBook_name()
- {
- return this.name;
- }
- public void setBook_name(String name)
- {
- this.name=name;
- }
- public List<BookType> getBookType()
- {
- return this.bookType;
- }
- public void setUser(List<BookType> bookType)
- {
- this.bookType=bookType;
- }
- public String toString()
- {
- return "Book [book_id="+id+",user_id="+user_id+",book_name="+name+",bookType="+bookType+"]";
- }
- }
3.建立BookType类,这里需要添加一个关联对象属性types,即typeid属性与type对象对应
- package com.mybatis.model.impl;
- public class BookType {
- public Integer id;
- public String book_id;
- public Integer type;
- public Type types;
- public Integer getId()
- {
- return this.id;
- }
- public void setId(Integer id)
- {
- this.id=id;
- }
- public String getBook_id()
- {
- return this.book_id;
- }
- public void setBook_id(String book_id)
- {
- this.book_id=book_id;
- }
- public Integer getType()
- {
- return this.type;
- }
- public void setTypeid(Integer type)
- {
- this.type=type;
- }
- public Type getTypes()
- {
- return this.types;
- }
- public void setTypes(Type types)
- {
- this.types=types;
- }
- public String toString()
- {
- return "BookType [book_id="+book_id+",type_id="+type+",typename="+types.getName()+"]";
- }
- }
4.建立Type类
- package com.mybatis.model.impl;
- public class Type {
- public Integer id;
- public String name;
- 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;
- }
- }
2.建立mapper接口
这里暂时只需要查询每个人对应的书及其种类的关系,因此一个方法即可搞定。接口定义如下:
- package com.mybatis.mapper;
- import java.util.*;
- import com.mybatis.model.impl.*;
- public interface BookOfUserMapper {
- public List<User1> getInfo();
- }
3.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 user.id user_id,user.name,book.id book_id,book.name book_name,booktype.type typeid,type.name type_name
- from book,booktype,user,type
- where user.id=book.user_id
- and book.id=booktype.book_id
- and booktype.type=type.id;
- </select>
- <resultMap type="com.mybatis.model.impl.User1" id="user1">
- <id property="id" column="user_id"/>
- <result property="name" column="user_name"/>
- <collection property="book" ofType="com.mybatis.model.impl.Book1">
- <id property="id" column="book_id"/>
- <result property="name" column="book_name"/>
- <collection property="bookType" ofType="com.mybatis.model.impl.BookType">
- <id property="book_id" column="book_id"/>
- <result property="type" column="typeid"/>
- <association property="types" javaType="com.mybatis.model.impl.Type">
- <id property="id" column="typeid"/>
- <result property="name" column="type_name"/>
- </association>
- </collection>
- </collection>
- </resultMap>
- </mapper>
上述mapper文件需要注意的是collection的填写,需要看其属性的层次,比如book是user的集合属性,是最外层的,而book中有个booktype集合属性,那么需要在外围的<collection...>元素中嵌套一个<collection元素>,又因为在内层collection中有一个关联对象type,则需要在内层<collection>元素中嵌套一个<association...>元素。注意嵌套与属性映射的关系。另外每个属性对应的column值则需要与sql查询语句中查询结果对应的列名相等。通过这个mapper文件,就相当于将整个复杂的表之间的关系全部映射到了User1对象中。
4.mybatis配置文件
将相应的mapper文件加载进去即可:
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE configuration
- PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
- "http://mybatis.org/dtd/mybatis-3-config.dtd">
- <!-- XML配置文件包含对MyBatis系统的核心设置 -->
- <configuration>
- <!-- 指定MyBatis所用日志的具体实现 -->
- <settings>
- <setting name="logImpl" value="LOG4J"/>
- <setting name="cacheEnabled" value="false"/>
- </settings>
- <environments default="development">
- <environment id="development">
- <transactionManager type="JDBC">
- </transactionManager>
- <dataSource type="POOLED">
- <property name="driver" value="org.gjt.mm.mysql.Driver"/>
- <property name="url" value="jdbc:mysql://localhost:3306/mybatisquery?characterEncoding=UTF-8"/>
- <property name="username" value="root"/>
- <property name="password" value="root"/>
- </dataSource>
- </environment>
- </environments>
- <mappers>
- <mapper resource="mapper/BookOfUserMapper.xml"/>
- </mappers>
- </configuration>
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: 10
- [User [user_id=1001,name=null,book=[Book [book_id=2001,user_id=null,book_name=算法导论,bookType=[BookType [book_id=2001,type_id=2,typename=算法]]], Book [book_id=2002,user_id=null,book_name=西游记,bookType=[BookType [book_id=2002,type_id=1,typename=名著]]]]], User [user_id=1002,name=null,book=[Book [book_id=2003,user_id=null,book_name=设计模式,bookType=[BookType [book_id=2003,type_id=2,typename=算法]]], Book [book_id=2004,user_id=null,book_name=编程思想,bookType=[BookType [book_id=2004,type_id=2,typename=算法]]]]], User [user_id=1003,name=null,book=[Book [book_id=2005,user_id=null,book_name=MySQL,bookType=[BookType [book_id=2005,type_id=2,typename=算法]]]]]]
该运行结果以集合的形式保存的,仔细查看会发现该结果与之前在sql中查询的结果一致。
6.实例文件结构