版权声明:转载请注明原始链接 https://blog.csdn.net/sswqzx/article/details/83792954
1、概述
数据库中多表之间存在着三种关系。如图
Mybatis作为一个持久层框架、对sql的多表查询提供了支持、下面学习mybatis一对一、一对多、多对多查询
2、一对一查询
订单和用户表中、从订单方向看、一个订单只属于一个用户、订单和用户是一对一的关系
需求:查询订单、同时还要查询出订单所属的用户信息
实体类:Order User
Order.java
package com.sswblog.domain;
/**
* @ Author :ShaoWei Sun.
* @ Date :Created in 21:13 2018/11/6
*/
public class Order {
private Integer id;
private User user;
private String orderNumber;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getOrderNumber() {
return orderNumber;
}
public void setOrderNumber(String orderNumber) {
this.orderNumber = orderNumber;
}
@Override
public String toString() {
return "Order{" +
"id=" + id +
", user=" + user +
", orderNumber='" + orderNumber + '\'' +
'}';
}
}
User.java
package com.sswblog.domain;
import java.io.Serializable;
import java.util.Date;
/**
* @ Author :ssw.
* @ Date :Created in 19:44 2018/11/4
*/
public class User implements Serializable {
private static final long serialVersionUid = 1L;
private Long id;
private String userName;
private String password;
private String name;
private Integer age;
private Integer sex;
private Date birthday;
private Date created;
private Date updated;
public static long getSerialVersionUid() {
return serialVersionUid;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public Date getUpdated() {
return updated;
}
public void setUpdated(Date updated) {
this.updated = updated;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", userName='" + userName + '\'' +
", password='" + password + '\'' +
", name='" + name + '\'' +
", age=" + age +
", sex=" + sex +
", birthday=" + birthday +
", created=" + created +
", updated=" + updated +
'}';
}
}
接口UserMapperTable.java
package com.sswblog.dao;
import com.sswblog.domain.Order;
import org.apache.ibatis.annotations.Param;
/**
* @ Author :ShaoWei Sun.
* @ Date :Created in 21:16 2018/11/6
*/
public interface UserMapperTable {
/**
* 通过订单号查询订单信息及订单所属的用户信息
* @param orderNumber
* @return
*/
public Order findOrderUserByNumber(@Param("orderNumber")String orderNumber);
}
编写接口映射文件UserMapperTable.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="com.sswblog.dao.UserMapperTable">
<resultMap id="userMap" type="Order" autoMapping="true">
<id column="id" property="id" />
<!--mybatis主配置文件没有开启驼峰、这里就要加上result-->
<result column="order_number" property="orderNumber"/>
<!--association:一对一映射-->
<!--property:order类中关联的另一个属性名-->
<!--javaType:order类中关联的另一个属性的类型-->
<!--autoMapping:开启自动映射-->
<association property="user" javaType="User" autoMapping="true">
<id column="user_id" property="id" />
<result column="user_name" property="userName" />
</association>
</resultMap>
<!--根据订单号查询订单信息以及订单所属的用户/一对一查询tb_order和tb_user表-->
<select id="findOrderUserByNumber" resultMap="userMap">
select * from tb_user u LEFT JOIN tb_order o ON u.id = o.id where o.order_number = #{orderNumber}
</select>
</mapper>
测试类UserMapperTableTest.java
package com.sswblog.test;
import com.sswblog.dao.UserMapperTable;
import com.sswblog.domain.Order;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
/**
* @ Author :ShaoWei Sun.
* @ Date :Created in 21:16 2018/11/6
*/
public class UserMapperTableTest {
private UserMapperTable userMapperTable = null;
@Before
public void setup() throws IOException {
//读取mybatis核心配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
//创建工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
//获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//
userMapperTable = sqlSession.getMapper(UserMapperTable.class);
}
@Test
public void findOrderUserByNumber(){
Order order = userMapperTable.findOrderUserByNumber("20140921001");
System.out.println("order = " + order);
}
}
3、一对多查询
订单表、订单详情表、从订单的角度来看、订单和订单详情是一对多的关系、一个订单有很多订单详情
需求:查询订单、同时还要查询出该订单下的订单详情信息
表关系
实体类:
tb_orderdetail.java
package com.sswblog.domain;
/**
* @ Author :ShaoWei Sun.
* @ Date :Created in 8:16 2018/11/7
*/
public class OrderDetail {
private Integer id;
private Double totalPrice;
private Integer status;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Double getTotalPrice() {
return totalPrice;
}
public void setTotalPrice(Double totalPrice) {
this.totalPrice = totalPrice;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
@Override
public String toString() {
return "OrderDetail{" +
"id=" + id +
", totalPrice=" + totalPrice +
", status=" + status +
'}';
}
}
Order.java
package com.sswblog.domain;
import java.util.List;
/**
* @ Author :ShaoWei Sun.
* @ Date :Created in 21:13 2018/11/6
*/
public class Order {
private Integer id;
private User user;
private String orderNumber;
private List<OrderDetail> orderDetails;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getOrderNumber() {
return orderNumber;
}
public void setOrderNumber(String orderNumber) {
this.orderNumber = orderNumber;
}
public List<OrderDetail> getOrderDetails() {
return orderDetails;
}
public void setOrderDetails(List<OrderDetail> orderDetails) {
this.orderDetails = orderDetails;
}
@Override
public String toString() {
return "Order{" +
"id=" + id +
", user=" + user +
", orderNumber='" + orderNumber + '\'' +
", orderDetails=" + orderDetails +
'}';
}
}
编写接口UserMapperTable.java
package com.sswblog.dao;
import com.sswblog.domain.Order;
import org.apache.ibatis.annotations.Param;
/**
* @ Author :ShaoWei Sun.
* @ Date :Created in 21:16 2018/11/6
*/
public interface UserMapperTable {
/**
* 一对一查询
* 通过订单号查询订单信息及订单所属的用户信息
* @param orderNumber
* @return
*/
public Order findOrderUserByNumber(@Param("orderNumber")String orderNumber);
/**
* 一对多查询
* 根据订单号查询订单信息及该订单所属的用户及该订单下的详情信息
* @param orderNumber
* @return
*/
public Order findOrderUserDetailByNumber(@Param("orderNumber")String orderNumber);
}
编写接口映射文件UserMapperTable.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="com.sswblog.dao.UserMapperTable">
<resultMap id="userMap1" type="Order" autoMapping="true">
<id column="id" property="id" />
<!--mybatis主配置文件没有开启驼峰、这里就要加上result-->
<result column="order_number" property="orderNumber"/>
<!--association:一对一映射-->
<!--property:order类中关联的另一个属性名-->
<!--javaType:order类中关联的另一个属性的类型-->
<!--autoMapping:开启自动映射-->
<association property="user" javaType="User" autoMapping="true">
<id column="user_id" property="id" />
<result column="user_name" property="userName" />
</association>
</resultMap>
<!--根据订单号查询订单信息以及订单所属的用户/一对一查询tb_order和tb_user表-->
<select id="findOrderUserByNumber" resultMap="userMap1">
select
*
from
tb_user u
LEFT JOIN
tb_order o ON u.id = o.id
where
o.order_number = #{orderNumber}
</select>
<!--一对多、表关系重要-->
<resultMap id="userMap2" type="Order" autoMapping="true">
<id column="id" property="id" />
<association property="user" javaType="User" autoMapping="true" >
<id column="user_id" property="id"/>
</association>
<collection property="orderDetails" javaType="list" ofType="OrderDetail" autoMapping="true" >
<id column="detail_id" property="id"/>
</collection>
</resultMap>
<!--根据订单号查询订单详情及该订单所属的用户及该订单下的详细信息-->
<select id="findOrderUserDetailByNumber" resultMap="userMap2">
select
*,c.id as detail_id
from
tb_order a
left join
tb_user b on a.user_id = b.id
left join
tb_orderdetail c on a.id = c.id
where
a.order_number = #{orderNumber}
</select>
</mapper>
测试类
package com.sswblog.test;
import com.sswblog.dao.UserMapperTable;
import com.sswblog.domain.Order;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
/**
* @ Author :ShaoWei Sun.
* @ Date :Created in 21:16 2018/11/6
*/
public class UserMapperTableTest {
private UserMapperTable userMapperTable = null;
@Before
public void setup() throws IOException {
//读取mybatis核心配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
//创建工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
//获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//
userMapperTable = sqlSession.getMapper(UserMapperTable.class);
}
/**
* 一对一查询
* 通过订单号查询订单信息及订单所属的用户信息
* @param
* @return
*/
@Test
public void findOrderUserByNumber(){
Order order = userMapperTable.findOrderUserByNumber("20140921001");
System.out.println("order = " + order);
}
/**
* 一对多查询
* 根据订单号查询订单信息及该订单所属的用户及该订单下的详情信息
* @param
* @return
*/
@Test
public void findOrderUserDetailByNumber(){
Order order = userMapperTable.findOrderUserDetailByNumber("20140921002");
System.out.println("order = " + order);
}
}
4、多对多查询
订单表、商品表、一个订单可以有多个商品、一个商品可以属于多个订单、所以是多对多关系
需求:查询订单、同时查询出订单下的商品信息
表间关系图:
实体类:
Item.java
package com.sswblog.domain;
/**
* @ Author :ShaoWei Sun.
* @ Date :Created in 9:40 2018/11/7
*/
public class Item {
private Integer id;
private String itemName;
private Float itemPrice;
private String itemDetail;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public Float getItemPrice() {
return itemPrice;
}
public void setItemPrice(Float itemPrice) {
this.itemPrice = itemPrice;
}
public String getItemDetail() {
return itemDetail;
}
public void setItemDetail(String itemDetail) {
this.itemDetail = itemDetail;
}
@Override
public String toString() {
return "Item{" +
"id=" + id +
", itemName='" + itemName + '\'' +
", itemPrice=" + itemPrice +
", itemDetail='" + itemDetail + '\'' +
'}';
}
}
改造OrderDetail.java
package com.sswblog.domain;
/**
* @ Author :ShaoWei Sun.
* @ Date :Created in 8:16 2018/11/7
*/
public class OrderDetail {
private Integer id;
private Double totalPrice;
private Integer status;
private Item item;//订单详情所属的商品
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Double getTotalPrice() {
return totalPrice;
}
public void setTotalPrice(Double totalPrice) {
this.totalPrice = totalPrice;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public Item getItem() {
return item;
}
public void setItem(Item item) {
this.item = item;
}
@Override
public String toString() {
return "OrderDetail{" +
"id=" + id +
", totalPrice=" + totalPrice +
", status=" + status +
", item=" + item +
'}';
}
}
接口UserMapperTable.java
package com.sswblog.dao;
import com.sswblog.domain.Order;
import org.apache.ibatis.annotations.Param;
/**
* @ Author :ShaoWei Sun.
* @ Date :Created in 21:16 2018/11/6
*/
public interface UserMapperTable {
/**
* 一对一查询
* 通过订单号查询订单信息及订单所属的用户信息
* @param orderNumber
* @return
*/
public Order findOrderUserByNumber(@Param("orderNumber")String orderNumber);
/**
* 一对多查询
* 根据订单号查询订单信息及该订单所属的用户及该订单下的详情信息
* @param orderNumber
* @return
*/
public Order findOrderUserDetailByNumber(@Param("orderNumber")String orderNumber);
/**
* 根据订单号查询订单信息以及该订单所属的用户及该订单下的详细信息以及商品信息
* @param orderNumber
* @return
*/
public Order findOrderUserDetailItemByNumber(@Param("orderNumber")String orderNumber);
}
Dao层接口映射文件UserMapperTable.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="com.sswblog.dao.UserMapperTable">
<resultMap id="userMap1" type="Order" autoMapping="true">
<id column="id" property="id" />
<!--mybatis主配置文件没有开启驼峰、这里就要加上result-->
<result column="order_number" property="orderNumber"/>
<!--association:一对一映射-->
<!--property:order类中关联的另一个属性名-->
<!--javaType:order类中关联的另一个属性的类型-->
<!--autoMapping:开启自动映射-->
<association property="user" javaType="User" autoMapping="true">
<id column="user_id" property="id" />
<result column="user_name" property="userName" />
</association>
</resultMap>
<!--根据订单号查询订单信息以及订单所属的用户/一对一查询tb_order和tb_user表-->
<select id="findOrderUserByNumber" resultMap="userMap1">
select
*
from
tb_user u
LEFT JOIN
tb_order o ON u.id = o.id
where
o.order_number = #{orderNumber}
</select>
<!--一对多、表关系重要-->
<resultMap id="userMap2" type="Order" autoMapping="true">
<id column="id" property="id" />
<association property="user" javaType="User" autoMapping="true" >
<id column="user_id" property="id"/>
</association>
<!--collection:一对多映射-->
<!--property属性:Order类中属性的名字-->
<!--javaTypen属性:集合的类型-->
<!--ofType属性:集合中元素的类型-->
<collection property="orderDetails" javaType="list" ofType="OrderDetail" autoMapping="true" >
<id column="detail_id" property="id"/>
</collection>
</resultMap>
<!--根据订单号查询订单详情及该订单所属的用户及该订单下的详细信息-->
<select id="findOrderUserDetailByNumber" resultMap="userMap2">
select
*,c.id as detail_id
from
tb_order a
left join
tb_user b on a.user_id = b.id
left join
tb_orderdetail c on a.id = c.id
where
a.order_number = #{orderNumber}
</select>
<resultMap id="userMap3" type="Order" autoMapping="true">
<id column="id" property="id"/>
<association property="user" javaType="User" autoMapping="true">
<id column="user_id" property="id"/>
</association>
<collection property="orderDetails" javaType="list" ofType="OrderDetail" autoMapping="true">
<id column="detail_id" property="id"/>
<association property="item" javaType="Item" autoMapping="true">
<id column="item_id" property="id"/>
</association>
</collection>
</resultMap>
<!--多对多查询-->
<select id="findOrderUserDetailItemByNumber" resultMap="userMap3">
select
*,c.id as detail_id
from
tb_order a
left join
tb_user b on a.user_id = b.id
left join
tb_orderdetail c on a.id = c.id
left join
tb_item d on c.item_id = d.id
where
a.order_number = #{orderNumber}
</select>
</mapper>
测试类:
package com.sswblog.test;
import com.sswblog.dao.UserMapperTable;
import com.sswblog.domain.Order;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
/**
* @ Author :ShaoWei Sun.
* @ Date :Created in 21:16 2018/11/6
*/
public class UserMapperTableTest {
private UserMapperTable userMapperTable = null;
@Before
public void setup() throws IOException {
//读取mybatis核心配置文件
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
//创建工厂
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
//获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//
userMapperTable = sqlSession.getMapper(UserMapperTable.class);
}
/**
* 一对一查询
* 通过订单号查询订单信息及订单所属的用户信息
* @param
* @return
*/
@Test
public void findOrderUserByNumber(){
Order order = userMapperTable.findOrderUserByNumber("20140921001");
System.out.println("order = " + order);
}
/**
* 一对多查询
* 根据订单号查询订单信息及该订单所属的用户及该订单下的详情信息
* @param
* @return
*/
@Test
public void findOrderUserDetailByNumber(){
Order order = userMapperTable.findOrderUserDetailByNumber("20140921002");
System.out.println("order = " + order);
}
/**
* 根据订单号查询订单信息以及该订单所属的用户及该订单下的详细信息以及商品信息
*/
@Test
public void findOrderUserDetailItemByNumber(){
Order order = userMapperTable.findOrderUserDetailItemByNumber("20140921002");
System.out.println("order = " + order);
}
}
补充:mybatis中的ResultMap继承
有的时候,在一个Mapper文件中会有多个resultMap有着相同的配置,此时我们可以采用继承的形式减少代码的冗余。
<resultMap id="orderUserMap" type="Order" autoMapping="true">
<id column="id" property="id"/>
<!--
association:一对一映射
property属性:Order类中关联的另一方的属性名
javaType属性:Order类中关联的另一方的属性的类型
autoMapping属性:开启自动映射
-->
<association property="user" javaType="User" autoMapping="true">
<id column="user_id" property="id"/>
</association>
</resultMap>
<resultMap id="orderUserDetailMap" type="Order" autoMapping="true" extends="orderUserMap">
<!--
collection:一对多映射
property属性:Order类中集合属性的名字
javaType属性:集合的类型
ofType属性:集合中元素的类型
-->
<collection property="orderdetails" javaType="list" ofType="Orderdetail" autoMapping="true">
<id column="detail_id" property="id"/>
</collection>
</resultMap>
<resultMap id="orderUserDetailItemMap" type="Order" autoMapping="true" extends="orderUserMap">
<collection property="orderdetails" javaType="list" ofType="Orderdetail" autoMapping="true">
<id column="detail_id" property="id"/>
<association property="item" javaType="Item" autoMapping="true">
<id column="item_id" property="id"/>
</association>
</collection>
</resultMap>