1.数据准备
商品订单数据模型:
建表语句
:
CREATE TABLE `items` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL COMMENT '商品名称',
`price` float(10,1) NOT NULL COMMENT '商品定价',
`detail` text COMMENT '商品描述',
`pic` varchar(64) DEFAULT NULL COMMENT '商品图片',
`createtime` datetime NOT NULL COMMENT '生产日期',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
/*Table structure for table `orderdetail` */
CREATE TABLE `orderdetail` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`orders_id` int(11) NOT NULL COMMENT '订单id',
`items_id` int(11) NOT NULL COMMENT '商品id',
`items_num` int(11) DEFAULT NULL COMMENT '商品购买数量',
PRIMARY KEY (`id`),
KEY `FK_orderdetail_1` (`orders_id`),
KEY `FK_orderdetail_2` (`items_id`),
CONSTRAINT `FK_orderdetail_1` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `FK_orderdetail_2` FOREIGN KEY (`items_id`) REFERENCES `items` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
/*Table structure for table `orders` */
CREATE TABLE `orders` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL COMMENT '下单用户id',
`number` varchar(32) NOT NULL COMMENT '订单号',
`createtime` datetime NOT NULL COMMENT '创建订单时间',
`note` varchar(100) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`),
KEY `FK_orders_1` (`user_id`),
CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
/*Table structure for table `user` */
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`birthday` date DEFAULT NULL COMMENT '生日',
`sex` char(1) DEFAULT NULL COMMENT '性别',
`address` varchar(256) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8;
````
数据准备:
<div class="se-preview-section-delimiter"></div>
insert into items
(id
,name
,price
,detail
,pic
,createtime
) values (1,’台式机’,3000.0,’该电脑质量非常好!!!!’,NULL,’2015-02-03 13:22:53’),(2,’笔记本’,6000.0,’笔记本性能好,质量好!!!!!’,NULL,’2015-02-09 13:22:57’),(3,’背包’,200.0,’名牌背包,容量大质量好!!!!’,NULL,’2015-02-06 13:23:02’);
/Data for the table orderdetail
/
insert into orderdetail
(id
,orders_id
,items_id
,items_num
) values (1,3,1,1),(2,3,2,3),(3,4,3,4),(4,4,2,3);
/Data for the table orders
/
insert into orders
(id
,user_id
,number
,createtime
,note
) values (3,1,’1000010’,’2015-02-04 13:22:35’,NULL),(4,1,’1000011’,’2015-02-03 13:22:41’,NULL),(5,10,’1000012’,’2015-02-12 16:13:23’,NULL);
/Data for the table user
/
insert into user
(id
,username
,birthday
,sex
,address
) values (1,’王五’,NULL,’2’,NULL),(10,’张三’,’2014-07-10’,’1’,’北京市’),(16,’张小明’,NULL,’1’,’河南郑州’),(22,’陈小明’,NULL,’1’,’河南郑州’),(24,’张三丰’,NULL,’1’,’河南郑州’),(25,’陈小明’,NULL,’1’,’河南郑州’),(26,’王五’,NULL,NULL,NULL);
<div class="se-preview-section-delimiter"></div>
### 2.一对一查询
<div class="se-preview-section-delimiter"></div>
#### 2.1 需求
查询订单信息关联查询用户信息
<div class="se-preview-section-delimiter"></div>
#### 2.2 sql语句
查询语句:
先确定主查询表:订单信息表
再确定关联查询表: 用户信息
通过Orders关联查询用户使用user_id 一个外键,只能关联查询出一条用户记录就可以使用内连接
<div class="se-preview-section-delimiter"></div>
SELECT
orders.*,
user.username,
user.sex
FROM
orders,
USER
WHERE orders.user_id = user.id
<div class="se-preview-section-delimiter"></div>
#### 2.3 使用resultType实现
<div class="se-preview-section-delimiter"></div>
##### 2.3.1 创建pojo
<div class="se-preview-section-delimiter"></div>
##### 2.3.2 一对一查询映射的pojo
创建pojo包括订单信息和用户信息,resultType才可以完成映射。
创建OrderCustomer作为自定义pojo,继承sql查询列多的pojo
<div class="se-preview-section-delimiter"></div>
public class OrderCustomer extends Orders{
//补充用户信息
private String username;
private String sex;
private String address;
}
““
2.3.3 mapper.xml
定义mapper.xml
<!--
一对一查询使用reusltType完成
查询订单关联查询用户信息
-->
<select id="findOrderUserList" resultType="orderCustom">
SELECT
orders.*,
user.username,
user.sex
FROM
orders,
USER
WHERE orders.user_id = user.id
</select>
2.3.4 mapper.java
public interface OrdersMapperCustomer{
//一对一查询,查询订单关联查询用户
public List<OrderCustomer> findOrderUserList() throws Exception;
}
2.4 使用resultMap实现一对一
2.4.1 resultMap映射思路
resultMap提供一对一关联查询的映射和一对多关联查询 樱花色,一对一映射思路:将关联查询的信息映射到pojo中,如下:
在orders中创建一个user属性,将关联查询的信息映射到User中
public class Orders{
private Integer id;
private Integer userId;
private String number;
private Date createTime;
private String note;
//关联用户信息
private User user;
}
2.4.2 mapper.xml
<!-- 一对一查询使用reusltMap完成
查询订单关联查询用户信息
-->
<select id="findOrderUserListResultMap" resultMap="ordersUserResultMap" >
SELECT
orders.*,
user.username,
user.sex
FROM
orders,
USER
WHERE orders.user_id = user.id
</select>
2.4.3 resultMap定义
<!-- 一对一查询resultMap -->
<resultMap type="orders" id="ordersUserResultMap">
<!-- 完成了订单信息的映射配置 -->
<!-- id:订单关联用户查询的唯 一 标识 -->
<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:用于对关联信息映射到单个pojo
property:要将关联信息映射到orders的哪个属性中
javaType:关联信息映射到orders的属性的类型,是user的类型
-->
<association property="user" javaType="user">
<!-- id:关联信息的唯 一标识 -->
<!-- property: 要映射到user的哪个属性中-->
<id column="user_id" property="id"/>
<!-- result就是普通列的映射 -->
<result column="username" property="username"/>
<result column="sex" property="sex"/>
</association>
</resultMap>
2.4.4 mapper.java
//一对一查询
public List<Orders> findOrderUserListResultMap() throws Exception;
2.5 小结
resultType:
要自定义pojo保证sql查询列和pojo的属性对应,这种方法相对简单,所以用用广泛。resultMap:
使用association完成一对一映射需要配置一个resultMap,过程有点复杂,如果要实现延迟加载就只能用resultMap实现,如果为了方便对关联信息进行解析,也可以用association将关联信息映射到pojo中方便解析。
3 一对多查询
3.1 需求
查询所有订单信息及订单写的订单明细信息。
3.2 sql语句
主查询表: 订单表
关联查询表: 订单明细
SELECT
orders.*,
user.username,
user.sex ,
orderdetail.id orderdetail_id,
orderdetail.items_num,
orderdetail.items_id
FROM
orders,
USER,
orderdetail
WHERE orders.user_id = user.id AND orders.id = orderdetail.orders_id
3.3 resultMap进行一对多映射思路
resultMap提供collection完成关联信息映射到集合对象。
在orders 类中创建集合属性:
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;
}
3.4 mapper.xml
<!-- 一对多查询使用reusltMap完成
查询订单关联查询订单明细
-->
<select id="findOrderAndOrderDetails" resultMap="orderAndOrderDetails" >
SELECT
orders.*,
user.username,
user.sex ,
orderdetail.id orderdetail_id,
orderdetail.items_num,
orderdetail.items_id
FROM
orders,
USER,
orderdetail
WHERE orders.user_id = user.id AND orders.id = orderdetail.orders_id
</select>
3.5 resultMap定义
<!-- 一对多,查询订单及订单明细 -->
<resultMap type="orders" id="orderAndOrderDetails" extends="ordersUserResultMap">
<!-- 映射订单信息,和用户信息,这里使用继承ordersUserResultMap -->
<!-- 映射订单明细信息
property:要将关联信息映射到orders的哪个属性中
ofType:集合中pojo的类型
-->
<collection property="orderdetails" ofType="cn.ty.mybatis.po.Orderdetail">
<!-- id:关联信息订单明细的唯 一标识
property:Orderdetail的属性名
-->
<id column="orderdetail_id" property="id"/>
<result column="items_num" property="itemsNum"/>
<result column="items_id" property="itemsId"/>
</collection>
</resultMap>
3.6 mapper.java
//一对多查询,使用resultMap
public List<Orders> findOrderAndOrderDetails() throws Exception;
4.一对多查询(复杂)
4.1 需求
查询所有用户信息,关联查询订单及订单明细及商品信息,订单明细信息中关联查询商品信息
4.2 sql
主查询表:用户信息
关联查询: 订单、订单明细,商品信息
SELECT
orders.*,
user.username,
user.sex ,
orderdetail.id orderdetail_id,
orderdetail.items_num,
orderdetail.items_id,
items.name items_name,
items.detail items_detail
FROM
orders,
USER,
orderdetail,
items
WHERE orders.user_id = user.id AND orders.id = orderdetail.orders_id AND items.id = orderdetail.items_id
4.3 pojo定义
在user.java中创建映射的属性:集合 List orderlist
在Orders中创建映射的属性:集合List orderdetails
在Orderdetail中创建商品属性:pojo Items items
public class User implements Serializable {
private int id;
private String username;// 用户姓名
private String sex;// 性别
private Date birthday;// 生日
private String address;// 地址
//多个订单
private List<Orders> orderlist;
}
public class Orders implements Serializable {
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
//关联用户信息
private User user;
//订单明细
private List<Orderdetail> orderdetails;
}
public class Orderdetail implements Serializable {
private Integer id;
private Integer ordersId;
private Integer itemsId;
private Integer itemsNum;
//商品信息
private Items items;
}
4.4 mapper.xml
<!-- 一对多查询使用reusltMap完成
查询用户及订单和订单明细,关联商品,的信息
-->
<select id="findUserOrderDetail" resultMap="userOrderDetailResultMap" >
SELECT
orders.*,
user.username,
user.sex ,
orderdetail.id orderdetail_id,
orderdetail.items_num,
orderdetail.items_id,
items.name items_name,
items.detail items_detail
FROM
orders,
USER,
orderdetail,
items
WHERE orders.user_id = user.id AND orders.id = orderdetail.orders_id AND items.id = orderdetail.items_id
</select>
4.5 resultMap
<!-- 一对多查询,查询用户及订单明细和商品信息 -->
<resultMap type="user" id="userOrderDetailResultMap">
<!-- 用户信息映射 -->
<id column="user_id" property="id"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
<!-- 订单信息 -->
<collection property="orderlist" ofType="cn.itcast.mybatis.po.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"/>
<!-- 订单明细映射 -->
<collection property="orderdetails" ofType="cn.itcast.mybatis.po.Orderdetail">
<!-- id:关联信息订单明细的唯 一标识
property:Orderdetail的属性名
-->
<id column="orderdetail_id" property="id"/>
<result column="items_num" property="itemsNum"/>
<result column="items_id" property="itemsId"/>
<!-- 商品信息 -->
<association property="items" javaType="cn.itcast.mybatis.po.Items">
<id column="item_id" property="id"/>
<result column="items_name" property="name"/>
<result column="items_detail" property="detail"/>
</association>
</collection>
</collection>
</resultMap>
4.6 mapper.java
//一对多查询
public List<User> findUserOrderDetail() throws Exception;
5. 延迟加载
5.1 使用延迟加载意义
在进行查询时,为了提高数据库查询性能,尽量使用单表查询,因为单表查询比多表查询速度更快。
如果查询单表就可以满足需求,一开始先查询单表,当需要关联信息时,再关联查询,当需要关联信息再查询这个叫延迟加载。
mybatis中resultMap提供延迟加载功能,通过resultMap配置延迟加载。
5.2 配置mybatis支持延迟加载
设置项 | 描述 | 允许值 | 默认值 |
---|---|---|---|
lazyLoadingEnabled | 全局性设置懒加载。如果设为false,则多有相关联的都会被初始化加载。 | true/false | false |
aggressiveLazyLoading | 当设置为true时,懒加载的对象可能被任何属性全部加载否则,每隔属性都按需加载 | true/false | true |
</br>
<!-- 全局配置参数 -->
<settings>
<!-- 延迟加载总开关 -->
<setting name="lazyLoadingEnabled" value="true" />
<!-- 设置按需加载 -->
<setting name="aggressiveLazyLoading" value="false" />
</settings>
5.3 延迟加载实现
5.3.1 实现思路
需求:
查询订单及用户的信息,一对一查询
刚开始查询订单信息。
当需要用户时调用Orders类中的getUser()方法执行延迟加载,向数据库发出sql
5.3.2 mapper.xml
<!-- 一对一查询延迟加载
开始只查询订单,对用户信息进行延迟加载
-->
<select id="findOrderUserListLazyLoading" resultMap="orderCustomLazyLoading">
SELECT
orders.*
FROM
orders
</select>
</mapper>
5.3.3 resultMap
<!-- 一对一查询延迟加载 的配置 -->
<resultMap type="orders" id="orderCustomLazyLoading">
<!-- 完成了订单信息的映射配置 -->
<!-- id:订单关联用户查询的唯 一 标识 -->
<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" />
<!-- 配置用户信息的延迟加载 select:延迟加载执行的sql所在的statement的id,如果不在同一个namespace需要加namespace
sql:根据用户id查询用户信息 column:关联查询的列 property:将关联查询的用户信息设置到Orders的哪个属性 -->
<association property="user"
select="cn.ty.mybatis.mapper.UserMapper.findUserById" column="user_id"></association>
</resultMap>
5.3.4 mapper.java
// 一对一查询,延迟加载
public List<Orders> findOrderUserListLazyLoading() throws Exception;
5.2.5 测试代码
// 一对一查询延迟加载
@Test
public void testFindOrderUserListLazyLoading() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 创建mapper代理对象
OrdersMapperCustom ordersMapperCustom = sqlSession
.getMapper(OrdersMapperCustom.class);
// 调用方法
List<Orders> list = ordersMapperCustom.findOrderUserListLazyLoading();
//这里执行延迟加载,要发出sql
User user = list.get(0).getUser();
System.out.println(user);
}
}
6 resultType、resultMap、延迟加载使用场景总结
延迟加载:
延迟加载实现的方法多种多样,在只查询单表就可以满足需求,为了提高数据库查询性能使用延迟加载,再查询关联信息。
mybatis提供延迟加载的功能用于service层。
resultType:
作用:
将查询结果按照sql列名pojo属性名一致性映射到pojo中
场合:
常见一些明细记录的展示,将关联查询信息全部展示在页面中,此时可直接使用resultType 将每一条记录映射到pojo中,在前端遍历list即可。
resultMap:
使用association 和 collection 完成一对一和一对多高级映射。
association:
作用:
将关联查询信息映射到一个pojo类
场合:
为了方便获取关联信息可以使用association将关联订单映射为pojo,比如查询订单及关联用户信息。
collection:
作用:
将关联查询信息映射到一个list集合中。
场合:
为了方便获取关联信息可以使用collection将关联信息映射到list集合中,比如:查询用户权限范围模块和功能,可使用collection将模块和功能列表映射到list中。