表介绍和表关系说明
新建以下4张表
tb_user:用户表
tb_order:订单表
tb_item:商品表
tb_orderdetail:订单详情表
【表关系】
1.tb_user和 tb_order表关系
tb_user 《==》 tb_order:一对多, 一个人可以下多个订单
tb_order 《==》 tb_user:一对一,一个订单只能属于一个人
结论:tb_user和tb_order属于一对多的关系,需要将一方tb_user的主键作为多方tb_order的外键维护关系
2.tb_order 和 tb_item 表关系
tb_order 《==》 tb_item :一个订单可以有多个商品
tb_item 《==》 tb_order:一个商品可以在多个订单上
结论:tb_order和tb_item属于多对多的关系,需要创建中间表tb_orderdetail维护两个表的关系,并且将两张表 的主键作为中间表的外键
一对一查询
需求:通过订单编号20140921003查询出订单信息,并查询出下单人信息。
【实现:关联查询】
【目标】使用多表关联查询,完成根据订单号查询订单信息和下单人信息(订单号:20140921003)
【分析】
一个订单编号对应一个订单,一个订单只能属于一个人。所以上述需求实现是一对一的实现。
【步骤】
1、首先,编写接口方法。编写SQL语句;
2、第二步:分析SQL,封装数据(关联对象);
3、处理多表之间的数据封装(数据库字段名---》实体类的属性名之间的映射)
【实现】
第一步:需求分析
编写多表关联查询SQL,根据订单号查询订单信息及下单人信息;
查询语句以及查询结果:
#方式一:分步查询
#第一步:根据order_number查询订单信息;
SELECT * FROM tb_order WHERE order_number = '20140921003';
#第二步:根据订单信息中的user_id查询出下单人的信息;
SELECT * FROM tb_user WHERE id = 1;
#方式二:多表关联查询,内连接
SELECT * FROM tb_order tbo inner join tb_user tbu on tbo.user_id = tbu.id where
tbo.order_number='20140921003'
#多表数据封装问题:
#关联对象封装数据(在Order中引用User)
第二步:添加关联
修改Order:
在Order类中,添加关联对象User,并添加getter和setter方法;
package com.itheima.sh.pojo;
/**
* 订单表
*
*/
public class Order {
private Integer id;
private String orderNumber;
//关联User对象
private User user;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getOrderNumber() {
return orderNumber;
}
public void setOrderNumber(String orderNumber) {
this.orderNumber = orderNumber;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
@Override
public String toString() {
return "Order{" +
"id=" + id +
", orderNumber='" + orderNumber + '\'' +
", user=" + user +
'}';
}
}
第三步:添加方法
编写OrderMapper接口
public interface OrderMapper {
/**
* 根据订单号查询订单及下单人的信息:方式二
* @param orderNumber
* @return
*/
Order queryOrderAndUserByOrderNumber2(@Param("orderNumber")String orderNumber);
}
第四步:编写SQL
在OrderMapper.xml中编写对应的SQL,并将OrderMapper.xml加入到mybatis-config.xml全局配置中;
【OrderMapper.xml代码;】
说明:
association:配置关联对象(User)的映射关系
<association property="user" javaType="User" autoMapping="true">
</association>
属性:
property:关联对象在主表实体类中的属性名;property="user" 表示在Order类中的引用的User类的对象 成员变量名
javaType:关联对象的类型;javaType="User" 表示引用的user对象属于User类型
-----------------------------------------------------------------------------------------
<?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">
<!--
映射文件
namespace 指定接口的类全名
-->
<mapper namespace="com.itheima.sh.dao.OrderMapper">
<!--
1.autoMapping="true" 表示只需要给当前表的id然后自动映射当前表的其他列值到
对应实体类的属性中,这属于偷懒行为,开发中我们最好都书写出来
2.id标签表示id的映射关系
3.result标签表示其他列和pojo类的属性映射关系
4.一对一映射关系使用子标签association来表示引用的另一个pojo类的对象
-->
<resultMap id="orderAndUserResultRelative" type="Order" autoMapping="true">
<!--主表主键-->
<id column="id" property="id"/>
<!--关联关系-->
<!--
1.property="user" 表示在Order类中的引用的User类的对象成员变量名
2.javaType="User" 表示引用的user对象属于User类型
-->
<association property="user" javaType="User" autoMapping="true">
<!--从表主键-->
<id column="id" property="id"/>
<!--<result column="user_name" property="userName"/>-->
</association>
</resultMap>
<!--多表关联查询:一对一-->
<select id="queryOrderAndUserByOrderNumber2" resultMap="orderAndUserResultRelative">
SELECT
*
FROM
tb_order tbo
INNER JOIN tb_user tbu ON tbo.user_id = tbu.id
WHERE
tbo.order_number = #{orderNumber}
</select>
</mapper>
说明:
1、由于queryOrderAndUserByOrderNumber2查询的结果Order对象中需要封装User信息,所以返回值不能够再使用单纯的resultType来操作;
2、定义resultMap进行关联查询的配置,其中:
属性:
id:标识这个resultMap;
type:返回的结果类型
autoMapping="true": 表示只需要给当前表的id然后自动映射当前表的其他列值到对应实体类的属性中,这 属于偷懒行为,开发中我们最好都书写出来
子元素:
id:主表主键映射
result:主表普通字段的映射
association:关联对象的映射配置
3、association:配置关联对象(User)的映射关系
属性:
property:关联对象在主表实体类中的属性名;property="user" 表示在Order类中的引用的User类的对象 成员变量名
javaType:关联对象的类型;javaType="User" 表示引用的user对象属于User类型
第五步:测试
package com.itheima.sh.test;
import com.itheima.sh.dao.OrderMapper;
import com.itheima.sh.dao.UserMapper;
import com.itheima.sh.pojo.Order;
import com.itheima.sh.pojo.User;
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.BeforeClass;
import org.junit.Test;
import java.io.InputStream;
public class MybatisTest02 {
private static OrderMapper mapper = null;
@BeforeClass
public static void beforeClass() throws Exception {
//1.构建SessionFactory
String resouce = "mybatis-config.xml";
InputStream is = Resources.getResourceAsStream(resouce);
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);
//2.获取session
SqlSession sqlSession = build.openSession(true);
//3.获取接口对象
mapper = sqlSession.getMapper(OrderMapper.class);
}
@Test
public void selectById() {
Order order = mapper.queryOrderAndUserByOrderNumber2("20140921003");
System.out.println("order = " + order);
}
}
【测试结果】
注意事项
通过上述测试结果,我们发现User的id是错误的,不是3,正确结果是1:
因为tb_user表的主键是id,tb_order的主键也是id。查询的结果中有两列相同的id字段。在将查询结果封装到实体类的过程中就会封装错误。
注意:user表查询的是id不是id1,由于SQLyog图形化界面显示的原因。可以在cmd窗口查看结果:
【解决方案】
1、建议将所要查询的所有字段显示地写出来;
2、将多表关联查询结果中,相同的字段名取不同的别名;
resultMap中应该如下配置:
【正确结果】
【小结】
一对一关联查询:
1、需要在Order实体类中关联User对象;最终将数据封装到Order中;
2、在OrderMapper.xml文件中书写关联语句并配置关系;
3、关联关系配置:
<resultMap id="orderAndUserResultRelative" type="Order" autoMapping="true">
<!--主表主键-->
<id column="oid" property="id"/>
<!--关联关系-->
<association property="user" javaType="User" autoMapping="true">
<!--从表主键-->
<id column="uid" property="id"/>
</association>
</resultMap>