一、数据模型分析思路
1、每张表记录的内容
分模块对每张表的内容进行熟悉,相当于学习系统需求(功能)的过程;
2、每张表的重要字段
非空字段、外键字段
3、数据库级别表与表之间的外键关系
4、数据库级别表与表之间的业务关系
一定是建立在业务意义的基础上;
先分析数据库级别有关联的表间的业务关系;
再分析数据库级别没有关联的表之间是否有业务关系;
二、商品订单数据模型
2.1、数据模型分析
2.2、一对一查询
2.2.1、需求
查询订单,并关联查询创建订单的用户信息
2.2.2、分析
查询的主表:订单表
查询的关联表:用户表
创建sql语句:
select
orders.*,
user.username,
user.sex,
user.address
from orders,user
where orders.user_id=user.id
2.2.2、resultType实现
1、创建POJO
package com.bird.po;
import java.util.Date;
/**
* @Author:wangqk
* @Date:2018/11/14 上午7:31
*/
public class Orders {
private Integer id;
private Integer userId;
private String number;
private Date createTime;
private String note;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}
package com.bird.po;
/**
* 映射订单和用户的查询结果,继承包含字段较多的pojo类
*
* @Author:wangqk
* @Date:2018/11/14 上午7:36
*/
public class OrdersCustom extends Orders {
private String userName;
private String sex;
private String address;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
2、创建mapper.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.bird.mapper.OrdersCustomerMapper">
<!-- 查询订单,关联查询用户 -->
<select id="findOrdersUser" resultType="com.bird.po.OrdersCustom">
select
orders.*,
user.username,
user.sex,
user.address
from orders, user
where orders.user_id = user.id
</select>
</mapper>
3、创建mapper.java
package com.bird.mapper;
import com.bird.po.OrdersCustom;
import java.util.List;
/**
* @Author:wangqk
* @Date:2018/11/14 上午7:53
*/
public interface OrdersCustomerMapper {
/**
* 查询订单,关联查询用户
*
* @return
* @throws Exception
*/
List<OrdersCustom> findOrdersUser() throws Exception;
}
4、单元测试
package com.bird.mapper;
import com.bird.po.OrdersCustom;
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.InputStream;
import java.util.List;
/**
* @Author:wangqk
* @Date:2018/11/14 上午7:57
*/
public class OrdersCustomMapperTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void setUp() throws Exception {
// mybatis配置文件
String resource = "SqlMapConfig.xml";
// 得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建会话工厂
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void findOrdersUserTest() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 创建代理对象
OrdersCustomMapper ordersCustomMapper = sqlSession.getMapper(OrdersCustomMapper.class);
// 调用mapper方法
List<OrdersCustom> list = ordersCustomMapper.findOrdersUser();
System.out.println(list);
sqlSession.close();
}
}
2.2.3、resultMap实现
使用resultMap将查询结果中的订单信息映射到Orders对象。
在Orders类中添加user属性,并将关联查询的用户信息映射到Orders对象的user属性中。
1、创建POJO(User类、Orders类)
package com.bird.po;
import java.util.Date;
/**
* @Author:wangqk
* @Date:2018/11/14 上午7:30
*/
public class User {
// 属性名和数据库表的字段名对应
private int id;
private String userName;
private String sex;
private Date birthday;
private String address;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
package com.bird.po;
import java.util.Date;
/**
* @Author:wangqk
* @Date:2018/11/14 上午7:31
*/
public class Orders {
private Integer id;
private Integer userId;
private String number;
private Date createTime;
private String note;
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}
2、创建mapper.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.bird.mapper.OrdersCustomMapper">
<!-- 查询订单关联用户:将查询结果集映射到com.bird.po.Orders中 -->
<resultMap id="OrdersUserResultMap" type="com.bird.po.Orders">
<!-- 配置映射的订单信息 -->
<!-- id指定查询字段中的唯一标识,如果有多个字段组成唯一标识,则配置多个id -->
<!-- column为订单信息的唯一标识字段,property为订单信息唯一标识字段所映射到Orders中的属性名 -->
<id column="id" property="id"/>
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
<result column="createtime" property="createTime"/>
<result column="note" property="note"/>
<!-- 配置映射的关联用户信息 -->
<!-- association关联查询单个对象的信息,property关联查询字段映射到Orders中的属性,javaType为映射到用户的属性名 -->
<association property="user" javaType="com.bird.po.User">
<!-- id为关联查询用户的唯一标识,column指定用户信息的唯一标识字段 -->
<id column="user_id" property="id"/>
<result column="username" property="userName"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
</association>
</resultMap>
<select id="findOrdersUser" resultMap="OrdersUserResultMap">
select
orders.*,
user.username,
user.sex,
user.address
from orders, user
where orders.user_id = user.id
</select>
</mapper>
3、创建mapper.java
package com.bird.mapper;
import com.bird.po.Orders;
import java.util.List;
/**
* @Author:wangqk
* @Date:2018/11/14 上午7:53
*/
public interface OrdersCustomMapper {
/**
* 查询订单,关联查询用户
*
* @return
* @throws Exception
*/
List<Orders> findOrdersUser() throws Exception;
}
4、单元测试同上。
2.2.4、总结resultType和resultMap实现一对一查询
resultType实现较为简单,如果pojo中没有包含查询字段,则要增加字段对应的属性名才能完成映射。如果没有查询结果的特殊要求,建议使用resultType。
resultMap实现较为复杂,需要单独定义resultMap。如果对查询结果有特殊的要求,使用resultMap可以完成将关联查询的结果集映射到pojo的属性中。
补充:resultMap可以实现延迟加载。
2.3、一对多查询
2.3.1、需求
查询订单及订单明细。
2.3.2、分析
查询的主表:订单表
查询的关联表:订单明细表
创建sql语句:
select
orders.*,
user.username,
user.sex,
user.address,
orderdetail.id as orderdetail_id,
orderdetail.items_id,
orderdetail.items_num,
orderdetail.orders_id
from
orders,
user,
orderdetail
where orders.user_id = user.id and orderdetail.orders_id = orders.id
2.3.3、 resultMap实现
1、创建POJO
package com.bird.po;
import java.util.Date;
import java.util.List;
/**
* @Author:wangqk
* @Date:2018/11/14 上午7:31
*/
public class Orders {
private Integer id;
private Integer userId;
private String number;
private Date createTime;
private String note;
// 用户信息
private User user;
// 订单明细
private List<OrderDetail> orderDetails;
public List<OrderDetail> getOrderDetails() {
return orderDetails;
}
public void setOrderDetails(List<OrderDetail> orderDetails) {
this.orderDetails = orderDetails;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}
2、创建mapper.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.bird.mapper.OrdersCustomMapper">
<!-- 查询订单关联用户:将查询结果集映射到com.bird.po.Orders中 -->
<resultMap id="OrdersUserResultMap" type="com.bird.po.Orders">
<!-- 配置映射的订单信息 -->
<!-- id指定查询字段中的唯一标识,如果有多个字段组成唯一标识,则配置多个id -->
<!-- column为订单信息的唯一标识字段,property为订单信息唯一标识字段所映射到Orders中的属性名 -->
<id column="id" property="id"/>
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
<result column="createtime" property="createTime"/>
<result column="note" property="note"/>
<!-- 配置映射的关联用户信息 -->
<!-- association关联查询单个对象的信息,property关联查询字段映射到Orders中的属性 -->
<association property="user" javaType="com.bird.po.User">
<!-- id为关联查询用户的唯一标识,column指定用户信息的唯一标识字段,javaType为映射到用户的属性名 -->
<id column="user_id" property="id"/>
<result column="username" property="userName"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
</association>
</resultMap>
<select id="findOrdersUser" resultMap="OrdersUserResultMap">
select
orders.*,
user.username,
user.sex,
user.address
from orders, user
where orders.user_id = user.id
</select>
<!-- 查询订单关联的用户及订单明细 -->
<!-- 使用extends继承,无需配置订单和用户信息的映射 -->
<resultMap id="OrdersAndOrderDetails" type="com.bird.po.Orders" extends="OrdersUserResultMap">
<!-- 订单信息 -->
<!-- 用户信息 -->
<!-- 订单明细信息 -->
<!-- 一个订单关联查询多条明细,使用collection进行一对多的映射 -->
<!--
collection将关联查询到的多条记录映射到集合对象
property将关联查询到的多条记录映射到属性名
ofType指定集合属性的pojo类型
-->
<collection property="orderDetails" ofType="com.bird.po.OrderDetail">
<!-- id为订单明细的唯一标识,property字段映射的属性名 -->
<id property="id" column="orderdetail_id"/>
<result column="items_id" property="itemsId"/>
<result column="items_num" property="itemsNum"/>
<result column="orders_id" property="ordersId"/>
</collection>
</resultMap>
<select id="findOrdersAndOrderDetails" resultMap="OrdersAndOrderDetails">
select
orders.*,
user.username,
user.sex,
user.address,
orderdetail.id as orderdetail_id,
orderdetail.items_id,
orderdetail.items_num,
orderdetail.orders_id
from
orders,
user,
orderdetail
where orders.user_id = user.id and orderdetail.orders_id = orders.id
</select>
</mapper>
3、创建mapper.java
package com.bird.mapper;
import com.bird.po.Orders;
import java.util.List;
/**
* @Author:wangqk
* @Date:2018/11/14 上午7:53
*/
public interface OrdersCustomMapper {
/**
* 查询订单,关联查询用户
*
* @return
* @throws Exception
*/
List<Orders> findOrdersUser() throws Exception;
/**
* 查询订单(关联用户)及订单明细
*
* @return
* @throws Exception
*/
List<Orders> findOrdersAndOrderDetails() throws Exception;
}
4、单元测试
package com.bird.mapper;
import com.bird.po.Orders;
import com.bird.po.OrdersCustom;
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.InputStream;
import java.util.List;
/**
* @Author:wangqk
* @Date:2018/11/14 上午7:57
*/
public class OrdersCustomMapperTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void setUp() throws Exception {
// mybatis配置文件
String resource = "SqlMapConfig.xml";
// 得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建会话工厂
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void findOrdersUserTest() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 创建代理对象
OrdersCustomMapper ordersCustomMapper = sqlSession.getMapper(OrdersCustomMapper.class);
// 调用mapper方法
List<Orders> list = ordersCustomMapper.findOrdersUser();
System.out.println(list);
sqlSession.close();
}
@Test
public void findOrdersAndOrderDetails() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 创建代理对象
OrdersCustomMapper ordersCustomMapper = sqlSession.getMapper(OrdersCustomMapper.class);
// 调用mapper方法
List<Orders> list = ordersCustomMapper.findOrdersAndOrderDetails();
System.out.println(list);
sqlSession.close();
}
}
2.4、多对多查询
2.4.1、需求
查询用户及购买商品信息
2.4.2、分析
查询的主表:用户表
查询的关联表:订单表、订单明细表、商品表
创建sql:
SELECT
orders.*,
USER.username,
USER.sex,
USER.address,
orderdetail.id orderdetail_id,
orderdetail.items_id,
orderdetail.items_num,
orderdetail.orders_id,
items.name items_name,
items.detail items_detail,
items.price items_price
FROM
orders,
USER,
orderdetail,
items
WHERE orders.user_id = user.id AND orderdetail.orders_id = orders.id AND orderdetail.items_id = items.id
2.4.3、resultMap实现
1、创建POJO
package com.bird.po;
import java.util.Date;
import java.util.List;
/**
* @Author:wangqk
* @Date:2018/11/14 上午7:30
*/
public class User {
// 属性名和数据库表的字段名对应
private int id;
private String userName;
private String sex;
private Date birthday;
private String address;
public List<Orders> getOrdersList() {
return ordersList;
}
public void setOrdersList(List<Orders> ordersList) {
this.ordersList = ordersList;
}
private List<Orders> ordersList;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
package com.bird.po;
import java.util.Date;
import java.util.List;
/**
* @Author:wangqk
* @Date:2018/11/14 上午7:31
*/
public class Orders {
private Integer id;
private Integer userId;
private String number;
private Date createTime;
private String note;
// 用户信息
private User user;
// 订单明细
private List<OrderDetail> orderDetails;
public List<OrderDetail> getOrderDetails() {
return orderDetails;
}
public void setOrderDetails(List<OrderDetail> orderDetails) {
this.orderDetails = orderDetails;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}
package com.bird.po;
/**
* @Author:wangqk
* @Date:2018/11/14 上午7:32
*/
public class OrderDetail {
private Integer id;
private Integer ordersId;
private Integer itemsId;
private Integer itemsNum;
// 明细对应的商品信息
private Items items;
public Items getItems() {
return items;
}
public void setItems(Items items) {
this.items = items;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getOrdersId() {
return ordersId;
}
public void setOrdersId(Integer ordersId) {
this.ordersId = ordersId;
}
public Integer getItemsId() {
return itemsId;
}
public void setItemsId(Integer itemsId) {
this.itemsId = itemsId;
}
public Integer getItemsNum() {
return itemsNum;
}
public void setItemsNum(Integer itemsNum) {
this.itemsNum = itemsNum;
}
}
package com.bird.po;
import java.util.Date;
/**
* @Author:wangqk
* @Date:2018/11/26 下午10:54
*/
public class Items {
private Integer id;
private String name;
private Float price;
private String pic;
private Date createTime;
private String detail;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Float getPrice() {
return price;
}
public void setPrice(Float price) {
this.price = price;
}
public String getPic() {
return pic;
}
public void setPic(String pic) {
this.pic = pic;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
}
2、创建mapper.xml
<!-- 查询用户及购买的商品 -->
<resultMap id="UserAndItems" type="com.bird.po.User">
<!-- 用户信息 -->
<id property="id" column="user_id"/>
<result column="username" property="userName"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
<!-- 订单信息 -->
<!-- 一个用户对应多个订单,使用collection映射 -->
<collection property="ordersList" ofType="com.bird.po.Orders">
<id column="id" property="id"/>
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
<result column="create_time" property="createTime"/>
<result column="note" property="note"/>
<!-- 订单明细 -->
<!-- 一个订单包含多个明细 -->
<collection property="orderDetails" ofType="com.bird.po.OrderDetail">
<id column="orderdetail_id" property="id"/>
<result column="items_id" property="itemsId"/>
<result column="items_num" property="itemsNum"/>
<result column="orders_id" property="ordersId"/>
<!-- 商品信息 -->
<!-- 一个订单明细对应一个商品 -->
<association property="items" javaType="com.bird.po.Items">
<id column="items_id" property="id"/>
<result column="items_name" property="name"/>
<result column="items_detail" property="detail"/>
<result column="items_price" property="price"/>
</association>
</collection>
</collection>
</resultMap>
<select id="findUserAndItems" resultMap="UserAndItems">
SELECT
orders.*,
USER.username,
USER.sex,
USER.address,
orderdetail.id orderdetail_id,
orderdetail.items_id,
orderdetail.items_num,
orderdetail.orders_id,
items.name items_name,
items.detail items_detail,
items.price items_price
FROM
orders,
USER,
orderdetail,
items
WHERE orders.user_id = user.id AND orderdetail.orders_id = orders.id AND orderdetail.items_id = items.id
</select>
3、创建mapper.java
package com.bird.mapper;
import com.bird.po.Orders;
import com.bird.po.User;
import java.util.List;
/**
* @Author:wangqk
* @Date:2018/11/14 上午7:53
*/
public interface OrdersCustomMapper {
List<User> findUserAndItems() throws Exception;
}
4、单元测试
package com.bird.mapper;
import com.bird.po.Orders;
import com.bird.po.OrdersCustom;
import com.bird.po.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.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.List;
/**
* @Author:wangqk
* @Date:2018/11/14 上午7:57
*/
public class OrdersCustomMapperTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void setUp() throws Exception {
// mybatis配置文件
String resource = "SqlMapConfig.xml";
// 得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建会话工厂
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void findUserAndItemsTest() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 创建代理对象
OrdersCustomMapper ordersCustomMapper = sqlSession.getMapper(OrdersCustomMapper.class);
// 调用mapper方法
List<User> list = ordersCustomMapper.findUserAndItems();
System.out.println(list);
sqlSession.close();
}
}
2.5、总结
resultType:将查询结果按照sql列名pojo属性名一致性映射到pojo中。
resultMap:使用association和collection完成一对一和一对多高级映射(对结果有特殊的映射要求)。
association:将关联查询信息映射到一个pojo对象中。
collection:将关联查询信息映射到一个list集合中。
三、延迟加载
3.1、什么是延迟加载
延迟加载:先从单表查询、需要时再从关联表去关联查询,大大提高 数据库性能,因为查询单表要比关联查询多张表速度快。
3.2、使用association实现延迟加载
3.2.1、需求
查询订单且关联查询用户信息