本文主要介绍了如何使用resultMap完成高级映射;分析数据库中表之间的关系(一对一、一对多、多对多)
如何在mapper.xml文件中配置resultMap实现一对一、一对多、多对多;mybatis如何实现延迟加载
数据库中有已经导入的四个表:items:(商品信息表);orderdetail:(订单明细表);orders:(订单表);user:(用户表)
1 CREATE TABLE items ( 2 id INT NOT NULL AUTO_INCREMENT, 3 itemsname VARCHAR(32) NOT NULL COMMENT '商品名称', 4 price FLOAT(10,1) NOT NULL COMMENT '商品定价', 5 detail TEXT COMMENT '商品描述', 6 pic VARCHAR(64) DEFAULT NULL COMMENT '商品图片', 7 createtime DATETIME NOT NULL COMMENT '生产日期', 8 PRIMARY KEY (id) 9 ) DEFAULT CHARSET=utf8; 10 11 /*Table structure for table `orderdetail` */ 12 13 CREATE TABLE orderdetail ( 14 id INT NOT NULL AUTO_INCREMENT, 15 orders_id INT NOT NULL COMMENT '订单id', 16 items_id INT NOT NULL COMMENT '商品id', 17 items_num INT DEFAULT NULL COMMENT '商品购买数量', 18 PRIMARY KEY (id), 19 KEY `FK_orderdetail_1` (`orders_id`), 20 KEY `FK_orderdetail_2` (`items_id`), 21 CONSTRAINT `FK_orderdetail_1` FOREIGN KEY (`orders_id`) REFERENCES `orders` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, 22 CONSTRAINT `FK_orderdetail_2` FOREIGN KEY (`items_id`) REFERENCES `items` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION 23 ) DEFAULT CHARSET=utf8; 24 25 /*Table structure for table `orders` */ 26 27 CREATE TABLE orders ( 28 id INT NOT NULL AUTO_INCREMENT, 29 user_id INT NOT NULL COMMENT '下单用户id', 30 number VARCHAR(30) NOT NULL COMMENT '订单号', 31 createtime DATETIME NOT NULL COMMENT '创建订单时间', 32 note VARCHAR(100) DEFAULT NULL COMMENT '备注', 33 PRIMARY KEY (`id`), 34 KEY `FK_orders_1` (`user_id`), 35 CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `t_user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION 36 ) DEFAULT CHARSET=utf8; 37 38 /*Table structure for table `t_user` */ 39 40 CREATE TABLE user ( 41 id INT NOT NULL AUTO_INCREMENT, 42 username VARCHAR(32) NOT NULL COMMENT '用户名称', 43 birthday DATE DEFAULT NULL COMMENT '生日', 44 sex CHAR(1) DEFAULT NULL COMMENT '性别', 45 address VARCHAR(256) DEFAULT NULL COMMENT '地址', 46 PRIMARY KEY (`id`) 47 ) DEFAULT CHARSET=utf8;
1 /*Data for the table `items` */ 2 3 INSERT INTO items(itemsname,price,detail,pic,createtime) VALUES 4 ('台式机',3000.0,'该电脑质量非常好!',NULL,'2015-07-07 13:28:53'), 5 ('笔记本',6000.0,'笔记本性能好,质量好!',NULL,'2015-07-08 13:22:57'), 6 ('背包',200.0,'名牌背包,容量大质量好!',NULL,'2015-07-010 13:25:02'); 7 8 /*Data for the table `orderdetail` */ 9 10 INSERT INTO `orderdetail`(`orders_id`,`items_id`,`items_num`) VALUES 11 (1,1,1), 12 (1,2,3), 13 (2,3,4), 14 (3,2,3); 15 16 /*Data for the table `orders` */ 17 18 INSERT INTO `orders`(`user_id`,`number`,`createtime`,`note`) VALUES 19 (1,'1000010','2015-06-04 13:22:35',NULL), 20 (1,'1000011','2015-07-08 13:22:41',NULL), 21 (2,'1000012','2015-07-17 14:13:23',NULL), 22 (3,'1000012','2015-07-16 18:13:23',NULL), 23 (4,'1000012','2015-07-15 19:13:23',NULL), 24 (5,'1000012','2015-07-14 17:13:23',NULL), 25 (6,'1000012','2015-07-13 16:13:23',NULL); 26 27 /*Data for the table `user` */ 28 29 INSERT INTO `user`(`username`,`birthday`,`sex`,`address`) VALUES 30 ('王五',NULL,'2',NULL), 31 ('张三','2014-07-10','1','北京市'), 32 ('张小明',NULL,'1','河南郑州'), 33 ('陈小明',NULL,'1','河南郑州'), 34 ('张三丰',NULL,'1','河南郑州'), 35 ('陈小明',NULL,'1','河南郑州'), 36 ('王五',NULL,NULL,NULL), 37 ('小A','2015-06-27','2','北京'), 38 ('小B','2015-06-27','2','北京'), 39 ('小C','2015-06-27','1','北京'), 40 ('小D','2015-06-27','2','北京');
用户表user:
记录了购买商品的用户
订单表orders:
记录了用户所创建的订单信息
订单明细表orderdetail:
记录了用户创建订单的详细信息
商品信息表items:
记录了商家提供的商品信息
分析表与表之间的关系:
用户user和订单orders:
user---->orders:一个用户可以创建多个订单 一对多
orders-->user:一个订单只能由一个用户创建 一对一
订单orders和订单明细orderdetail:
orders-->orderdetail:一个订单可以包括多个订单明细 一对多
orderdetail-->orders:一个订单明细只属于一个订单 一对一
订单明细orderdetail和商品信息items:
orderdetail-->items:一个订单明细对应一个商品信息一对一
items--> orderdetail:一个商品对应多个订单明细 一对多
以下是这四个表的对应关系:
使用Mapper接口代理的方式查询订单信息关联查询用户信息
查询语句:
先确定主查询表:订单信息表
再确定关联查询表:用户信息
通过orders关联查询用户使用user_id一个外键,只能关联查询出一条用户记录就可以使用内连接
SELECT
orders.*,
user.username,
user.sex
FROM
orders,
USER
WHERE orders.user_id = user.id
这里输出的结果包括 订单信息和用户信息,之前创建的pojo都是单表的实体类,所以这里需要自定义一个组合的pojo才能完成resultType的映射。
创建OrderCustom作为自定义pojo,补充相应的get()和set()方法
packagecn.itcast.mybatis.po;
public class OrderCustomextends Orders {
//补充用户信息
privateStringusername;
privateStringsex;
privateString address;
}
定义OrdersMapperCustom.xml文件,
<!--一对一查询使用reusltType完成
查询订单关联查询用户信息使用resultType的方式
-->
<selectid="findOrderUserList"resultType="orderCustom">
SELECT
orders.*,
user.username,
user.sex
FROM
orders,
USER
WHEREorders.user_id = user.id
</select>
定义OrderMapperCustomer.java文件
packagecn.itcast.mybatis.mapper;
public interfaceOrdersMapperCustom {
// 一对一查询,查询订单关联查询用户,使用resultType
publicList<OrderCustom> findOrderUserList()throwsException;
}
package cn.itcast.mybatis.mapper;
public class OrdersMapperCustomTest {
//会话工厂
privateSqlSessionFactory sqlSessionFactory;
//创建工厂
@Before
publicvoid init() throws IOException {
//配置文件(SqlMapConfig.xml)
Stringresource = "SqlMapConfig.xml";
//加载配置文件到输入流
InputStreaminputStream = Resources.getResourceAsStream(resource);
//创建会话工厂
sqlSessionFactory= new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
publicvoid testFindOrderUserList() throws Exception {
SqlSessionsqlSession = sqlSessionFactory.openSession();
//创建mapper代理对象
OrdersMapperCustomordersMapperCustom = sqlSession
.getMapper(OrdersMapperCustom.class);
//调用方法
List<OrderCustom>list = ordersMapperCustom.findOrderUserList();
System.out.println(list);
}
}
resultMap提供一对一关联查询的映射和一对多关联查询映射,一对一映射思路:将关联查询的信息映射到查询的POJO中,如下:
在Orders类中创建一个User属性,将关联查询的信息映射到User属性中。
Orders.java补充相应的get()和set()方法
package cn.itcast.mybatis.po;
public class Orders implements Serializable{
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
//关联用户信息
private User user;
}
OrdersMapperCustomer.xml定义sql语句以及resultMap映射之间的关系
<!-- 一对一查询resultMap,这里的ID是一个唯一的标识,与输出参数resultMap定义的相同(用黄色标出)
-->
<resultMaptype="orders"id="ordersUserResultMap">
<!--完成了订单信息的映射配置-->
<!--id:订单关联用户查询的唯一标识 -->
<!--column: sql语句中查询的列,property:pojo中对应的属性-->
<idcolumn="id"property="id"/>
<resultcolumn="user_id"property="userId"/>
<resultcolumn="number"property="number"/>
<resultcolumn="createtime"property="createtime"/>
<resultcolumn="note"property="note"/>
<!--下边完成关联信息的映射
association:用于对关联信息映射到单个pojo
property:要将关联信息映射到orders的哪个属性中
javaType:关联信息映射到orders的属性的类型,是user的类型
-->
<associationproperty="user"javaType="user">
<!--id:关联信息的唯一标识 -->
<!--property:要映射到user的哪个属性中-->
<idcolumn="user_id"property="id"/>
<!--result就是普通列的映射-->
<resultcolumn="username"property="username"/>
<resultcolumn="sex"property="sex"/>
</association>
</resultMap>
<!-- 一对一查询使用reusltMap完成
查询订单关联查询用户信息 -->
<selectid="findOrderUserListResultMap"resultMap="ordersUserResultMap">
SELECT
orders.*,
user.username,
user.sex
FROM
orders,
USER
WHEREorders.user_id = user.id
</select>
在OrderMapperCustomer.java中添加使用resultMap进行一对一查询的接口
packagecn.itcast.mybatis.mapper;
public interfaceOrdersMapperCustom {
// 一对一查询,使用resultMap
publicList<Orders> findOrderUserListResultMap()throwsException;
}
package cn.itcast.mybatis.mapper;
public class OrdersMapperCustomTest {
//会话工厂
privateSqlSessionFactory sqlSessionFactory;
//创建工厂
@Before
publicvoid init() throws IOException {
//配置文件(SqlMapConfig.xml)
Stringresource = "SqlMapConfig.xml";
// 加载配置文件到输入流
InputStreaminputStream = Resources.getResourceAsStream(resource);
//创建会话工厂
sqlSessionFactory= new SqlSessionFactoryBuilder().build(inputStream);
}
// 一对一查询使用resultMap
@Test
public voidtestFindOrderUserListResultMap() throwsException {
SqlSessionsqlSession = sqlSessionFactory.openSession();
// 创建mapper代理对象
OrdersMapperCustomordersMapperCustom = sqlSession
.getMapper(OrdersMapperCustom.class);
// 调用方法
List<Orders>list = ordersMapperCustom.findOrderUserListResultMap();
System.out.println(list);
}
}
resultType:要自定义pojo 保证sql查询列和pojo的属性对应,加入sql语句使用别名,则查询不到该列的信息,这种方法相对较简单,所以应用广泛。
resultMap:使用association完成一对一映射需要配置一个resultMap,过程有点复杂,如果要实现延迟加载就只能用resultMap实现 ,如果为了方便对关联信息进行解析,也可以用association将关联信息映射到pojo中方便解析。
使用mapper接口代理的方式查询所有订单信息(关联用户)及订单下的订单明细信息。
主查询表:订单表
关联查询表:订单明细
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
resultMap 提供collection完成关联信息映射到集合对象中。
在orders类中创建集合属性:
package cn.itcast.mybatis.po;
public class Orders implements Serializable{
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
//关联用户信息
private User user;
//订单明细
privateList<Orderdetail> orderdetails;
}
<!-- 一对多,查询订单及订单明细 -->
<resultMaptype="orders"id="orderAndOrderDetails"extends="ordersUserResultMap">
<!--映射订单信息,和用户信息,这里使用继承ordersUserResultMap-->
<!--映射订单明细信息
property:要将关联信息映射到orders的哪个属性中
ofType:集合中pojo的类型
-->
<collectionproperty="orderdetails"ofType="cn.itcast.mybatis.po.Orderdetail">
<!--id:关联信息订单明细的唯一标识
property:Orderdetail的属性名
-->
<idcolumn="orderdetail_id"property="id"/>
<resultcolumn="items_num"property="itemsNum"/>
<resultcolumn="items_id"property="itemsId"/>
</collection>
</resultMap>
<!-- 一对多查询使用reusltMap完成
查询订单关联查询订单明细
-->
<selectid="findOrderAndOrderDetails"resultMap="orderAndOrderDetails">
SELECT
orders.*,
user.username,
user.sex ,
orderdetail.id orderdetail_id,
orderdetail.items_num,
orderdetail.items_id
FROM
orders,
USER,
orderdetail
WHEREorders.user_id = user.id AND orders.id =orderdetail.orders_id
</select>
在OrderMapperCustomer.java中添加使用resultMap进行一对多查询的接口
packagecn.itcast.mybatis.mapper;
public interfaceOrdersMapperCustom {
// 一对多查询,使用resultMap
publicList<Orders> findOrderAndOrderDetails()throwsException;
}
package cn.itcast.mybatis.mapper;
public class OrdersMapperCustomTest {
//会话工厂
privateSqlSessionFactory sqlSessionFactory;
//创建工厂
@Before
publicvoid init() throws IOException {
//配置文件(SqlMapConfig.xml)
Stringresource = "SqlMapConfig.xml";
//加载配置文件到输入流
InputStreaminputStream = Resources.getResourceAsStream(resource);
//创建会话工厂
sqlSessionFactory= new SqlSessionFactoryBuilder().build(inputStream);
}
// 一对多查询使用resultMap
@Test
public voidtestFindOrderAndOrderDetails() throwsException {
SqlSessionsqlSession = sqlSessionFactory.openSession();
// 创建mapper代理对象
OrdersMapperCustomordersMapperCustom = sqlSession
.getMapper(OrdersMapperCustom.class);
// 调用方法
List<Orders>list = ordersMapperCustom.findOrderAndOrderDetails();
System.out.println(list);
}
}
mybatis使用resultMap的collection对关联查询的多条记录映射到一个list集合属性中。使用resultType实现:将订单明细映射到orders中的orderdetails中,需要自己处理,使用双重循环遍历,去掉重复记录,将订单明细放在orderdetails中。
查询所有用户信息,关联查询订单及订单明细信息及商品信息,订单明细信息中关联查询商品信息
主查询表:用户信息
关联查询:订单、订单明细,商品信息
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 ANDitems.id = orderdetail.items_id
一对多映射是多对对映射的一个特殊例子,多对多映射思路如下:
在user.java中创建映射的属性:集合 List<Orders>orderlist
在Orders中创建映射的属性:集合List<Orderdetail> orderdetails
在Orderdetail中创建商品属性:pojo Items items
User.java
package cn.itcast.mybatis.po;
public class User implements Serializable {
privateint id;
privateString username;// 用户姓名
privateString sex;// 性别
privateDate birthday;// 生日
privateString address;// 地址
//多个订单
private List<Orders> orderlist;
}
Orders.java
package cn.itcast.mybatis.po;
public class Orders implements Serializable{
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
//关联用户信息
private User user;
//订单明细
privateList<Orderdetail> orderdetails;
}
Orderdetail.java
packagecn.itcast.mybatis.po;
importjava.io.Serializable;
public class Orderdetailimplements Serializable {
privateIntegerid;
privateIntegerordersId;
privateIntegeritemsId;
privateIntegeritemsNum;
//商品信息
private Items items;
}
OrdersMapperCustomer.xml定义sql语句以及resultMap映射之间的关系
<!-- 多对多查询,查询用户及订单明细和商品信息-->
<resultMaptype="user"id="userOrderDetailResultMap">
<!--用户信息映射-->
<idcolumn="user_id"property="id"/>
<resultcolumn="username"property="username"/>
<resultcolumn="sex"property="sex"/>
<!--订单信息-->
<collectionproperty="orderlist"ofType="cn.itcast.mybatis.po.Orders">
<idcolumn="id"property="id"/>
<resultcolumn="user_id"property="userId"/>
<resultcolumn="number"property="number"/>
<resultcolumn="createtime"property="createtime"/>
<resultcolumn="note"property="note"/>
<!--订单明细映射-->
<collectionproperty="orderdetails"ofType="cn.itcast.mybatis.po.Orderdetail">
<!--id:关联信息订单明细的唯一标识
property:Orderdetail的属性名
-->
<idcolumn="orderdetail_id"property="id"/>
<resultcolumn="items_num"property="itemsNum"/>
<resultcolumn="items_id"property="itemsId"/>
<!--商品信息-->
<associationproperty="items"javaType="cn.itcast.mybatis.po.Items">
<idcolumn="item_id"property="id"/>
<resultcolumn="items_name"property="name"/>
<resultcolumn="items_detail"property="detail"/>
</association>
</collection>
</collection>
</resultMap>
<!--多对多查询使用reusltMap完成
查询用户及订单和订单明细,关联商品,的信息
-->
<selectid="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 ANDitems.id = orderdetail.items_id
</select>
在OrderMapperCustomer.java中添加使用resultMap进行一对多查询的接口
packagecn.itcast.mybatis.mapper;
public interfaceOrdersMapperCustom {
// 多对多查询,使用resultMap
publicList<User> findUserOrderDetail()throwsException;
}
package cn.itcast.mybatis.mapper;
public class OrdersMapperCustomTest {
//会话工厂
privateSqlSessionFactory sqlSessionFactory;
//创建工厂
@Before
publicvoid init() throws IOException {
//配置文件(SqlMapConfig.xml)
Stringresource = "SqlMapConfig.xml";
//加载配置文件到输入流
InputStreaminputStream = Resources.getResourceAsStream(resource);
//创建会话工厂
sqlSessionFactory= new SqlSessionFactoryBuilder().build(inputStream);
}
// 一对多查询使用resultMap
@Test
public voidtestFindUserOrderDetail() throwsException {
SqlSessionsqlSession = sqlSessionFactory.openSession();
// 创建mapper代理对象
OrdersMapperCustomordersMapperCustom = sqlSession
.getMapper(OrdersMapperCustom.class);
// 调用方法
List<User>list = ordersMapperCustom.findUserOrderDetail();
System.out.println(list);
}
}
在进行数据查询时,为了提高数据库查询性能,尽量使用单表查询,因为单表查询比多表关联查询速度要快。
如果查询单表就可以满足需求,一开始先查询单表,当需要关联信息时,再关联查询,当需要关联信息再查询这个叫延迟加载。
mybatis中resultMap提供延迟加载功能,通过resultMap配置延迟加载。
在SqlMapConfig.xml文件中配置延迟加载
<!-- 全局配置参数 -->
<settings>
<!-- 延迟加载总开关 -->
<settingname="lazyLoadingEnabled"value="true"/>
<!-- 设置按需加载 -->
<settingname="aggressiveLazyLoading"value="false"/>
</settings>
需求:查询订单及用户的信息,一对一查询。
刚开始只查询订单信息
当需要用户时调用 Orders类中的getUser()方法执行延迟加载 ,向数据库发出sql。
定义OrdersMapperCustom.xml文件,
<!-- 一对一查询延迟加载resultMap的配置-->
<resultMaptype="orders"id="orderCustomLazyLoading">
<!--完成了订单信息的映射配置-->
<!--id:订单关联用户查询的唯一标识-->
<idcolumn="id"property="id"/>
<resultcolumn="user_id"property="userId"/>
<resultcolumn="number"property="number"/>
<resultcolumn="createtime"property="createtime"/>
<resultcolumn="note"property="note"/>
<!--配置用户信息的延迟加载select:延迟加载执行的sql所在的statement的id,如果不在同一个namespace需要加namespace
sql:根据用户id查询用户信息column:关联查询的列property:将关联查询的用户信息设置到Orders的哪个属性-->
<associationproperty="user"
select="cn.itcast.mybatis.mapper.UserMapper.findUserById"column="user_id"></association>
</resultMap>
Sql语句的配置
<!-- 一对一查询延迟加载
开始只查询订单,对用户信息进行延迟加载
-->
<selectid="findOrderUserListLazyLoading"resultMap="orderCustomLazyLoading">
SELECT
orders.*
FROM
orders
</select>
在OrderMapperCustomer.java中添加使用延迟加载进行一对一查询的接口
packagecn.itcast.mybatis.mapper;
public interfaceOrdersMapperCustom {
//一对一查询,延迟加载
publicList<Orders> findOrderUserListLazyLoading()throwsException;
}
package cn.itcast.mybatis.mapper;
public class OrdersMapperCustomTest {
//会话工厂
privateSqlSessionFactory sqlSessionFactory;
//创建工厂
@Before
publicvoid init() throws IOException {
//配置文件(SqlMapConfig.xml)
Stringresource = "SqlMapConfig.xml";
//加载配置文件到输入流
InputStreaminputStream = Resources.getResourceAsStream(resource);
//创建会话工厂
sqlSessionFactory= new SqlSessionFactoryBuilder().build(inputStream);
}
// 一对一查询延迟加载
@Test
public voidtestFindOrderUserListLazyLoading() throwsException {
SqlSessionsqlSession = sqlSessionFactory.openSession();
// 创建mapper代理对象
OrdersMapperCustomordersMapperCustom = sqlSession
.getMapper(OrdersMapperCustom.class);
// 调用方法
List<Orders>list = ordersMapperCustom.findOrderUserListLazyLoading();
//这里执行延迟加载,要发出sql
Useruser = list.get(0).getUser();
System.out.println(user);
}
}
延迟加载:
延迟加载实现的方法多种多样,在只查询单表就可以满足需求,为了提高数据库查询性能使用延迟加载,再查询关联信息。
mybatis提供延迟加载的功能用于service层。
resultType:
作用:
将查询结果按照sql列名pojo属性名一致性映射到pojo中。
场合:
常见一些明细记录的展示,将关联查询信息全部展示在页面时,此时可直接使用resultType将每一条记录映射到pojo中,在前端页面遍历list(list中是pojo)即可。
resultMap:
使用association和collection完成一对一和一对多高级映射。
association:
作用:
将关联查询信息映射到一个pojo类中。
场合:
为了方便获取关联信息可以使用association将关联订单映射为pojo,比如:查询订单及关联用户信息。
collection:
作用:
将关联查询信息映射到一个list集合中。
场合:
为了方便获取关联信息可以使用collection将关联信息映射到list集合中,比如:查询用户权限范围模块和功能,可使用collection将模块和功能列表映射到list中。