MyBatis 由浅入深(实践篇)-3

来源:转载

MyBatis 高级知识
开发环境


[Java环境] :jdk1.8.0_91
[开发工具] : IDEA 2016.2.5
[数据库] : MySQL 5.7.13
[项目管理工具]:Maven 3.1.1



数据库
--Table structure for tb_items
DROP TABLE IF EXISTS `tb_items`;
CREATE TABLE `tb_items` (
`id` int(11) NOT NULL,
`name` varchar(255) DEFAULT NULL COMMENT '商品名',
`price` float(10,1) DEFAULT NULL COMMENT '价格',
`detail` varchar(255) DEFAULT NULL COMMENT '商品介绍',
`stock` int(255) DEFAULT NULL COMMENT '库存',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- Table structure for tb_orderdetail
DROP TABLE IF EXISTS `tb_orderdetail`;
CREATE TABLE `tb_orderdetail` (
`id` int(11) NOT NULL,
`order_id` int(11) NOT NULL COMMENT '订单id',
`item_id` int(11) NOT NULL COMMENT '商品id',
`count` int(11) DEFAULT NULL COMMENT '订单量',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- Table structure for tb_orders
DROP TABLE IF EXISTS `tb_orders`;
CREATE TABLE `tb_orders` (
`id` int(11) NOT NULL,
`userId` int(11) NOT NULL,
`number` varchar(255) DEFAULT NULL COMMENT '订单号',
`createtime` date DEFAULT NULL,
`note` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- Table structure for tb_user
DROP TABLE IF EXISTS `tb_user`;
CREATE TABLE `tb_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL,
`sex` varchar(10) DEFAULT NULL,
`birthday` date DEFAULT NULL,
`address` varchar(500) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

用户表 tb_user:记录用户信息
订单表 tb_orders:记录用户所创建的订单(购买商品的订单)
订单明细表 tb_orderdetail:记录了订单的详细信息即购买商品的信息
商品表 tb_items:记录了商品信息



表之间的关联关系

实际业务中,实体与实体之间存在一定的业务关系(一对一,一对多,多对多),而关系性数据库通常是根据业务实体建表,所以上述几个关系也可以用来形容表之间的关联关系。


那么根据上述所建的 订单类业务表分析:


用户(tb_user) 和 订单 (tb_orders)
一个用户可以有多个订单(一对多)
一个订单只能由一个用户创建(一对一)
订单(tb_orders) 和 订单详情(tb_orderdetail)
一个订单可以有多个订单明细(一对多)
一个订单明细只能属于一个订单(一对一)
订单详情(tb_orderdetail) 和 商品(tb_items)
一个订单明细只能对应一个商品(一对一)
一个商品可以包含在多个订单明细中(一对多)
订单(tb_orders) 和 商品(tb_items)
一个订单可以包含多个商品,同理一个商品可以被多个订单包含(多对多)

订单(tb_orders) 和 商品(tb_items)之间的这种多对多关系在很多实际业务中不利于DTO数据建模及开发维护,此时,使用订单详情(tb_orderdetail) 可以将 一个多对多关系拆分成两个一对多关系。
将多对多关系拆分成一对多关系,是简化数据库实体建模常用的一种方式



复杂数据模型

在实际开发过程中,经常从多个有关联关系的表中提取出符合业务需求的数据,此时需要将返回的数据封装成一个对象,此时这个对象就需要针对表关联关系(一对一,一对多,多对多)进行设计。
如何使用 MyBatis 将这个包含关联关系的复杂对象与 sql 返回数据进行绑定,使程序运行时自动映射成该对象实例呢?


一对一查询

业务需求:查询订单列表用户及下订单的用户信息


sql 实现业务:


SELECT orders.*, USER.username, USER.sex, USER.address FROM tb_orders orders, tb_user user WHERE orders.userId = user.id使用 resultType

1.创建实体对象(pojo)


Order.java


import cn.guan.mybatis.example2.User;
import java.util.Date;
import java.util.List;
/**
*订单实体类
**/
public class Order {
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
//用户信息
private User user;
//订单明细
private List orderdetails;
//setter and getter and toString
···
}

Orderdetail.java


**
* 订单详情实体类
**/
public class Orderdetail {
private Integer id;
private Integer order_id;
private Integer itemsId;
private Integer count;
//明细对应的商品信息
private Item items;
//setter and getter and toString
···
}

Item.java


/**
* 商品实体类
**/
public class Item {
private Integer id;
private String name;
private Float price;
private String detail;
private Integer stock;

//setter and getter and toString
···
}

OrderCustom.java


/**
* @Description : 通过此类映射订单和用户查询的结果,让此类继承包括 字段较多的pojo类
*/
public class OrderCustom extends Order{
//用户属性
private String username;
private String sex;
private String address;
//setter and getter and toString
···
}

2.创建 Mapper 接口
OrderCustomMapper.java


/**
*@Description : mapper 接口
*/
public interface OrderCustomMapper {
OrderCustom findOrdersUserByResultType() throws Exception;
}

3.创建 Mapper 接口对应 *-mapper.xml 并配置 路径
ordercustom-mapper.xml


<?xml version="1.0" encoding="utf-8" ?>
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">





mybatis-config.xml 中配置加载路径






4.测试


MyBatisMappingTest.java


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;
/**
* @Description : MyBatis 多种映射关系测试
*/
public class MyBatisMappingTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void init() throws Exception
{
//创建sqlSessionFactory
//Mybatis 配置文件
String resource = "mybatis-config.xml";
//得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
//创建会话工厂,传入Mybatis的配置文件信息
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testOne2One(){
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建usermapper对象,mybatis自动生成代理对象
OrderCustomMapper orderCustomMapper = sqlSession.getMapper(OrderCustomMapper.class);
//调用UserMapper的方法
OrderCustom orderCustom = null;
try {
orderCustom = orderCustomMapper.findOrdersUserByResultType();
System.out.println(orderCustom);
} catch (Exception e) {
e.printStackTrace();
}
}
}使用 resultMap

使用 resultMap 将查询结果中的订单信息映射到 Orders 对象中,在 orders 类中添加 User 属性,将关联查询出来的用户信息映射到 orders 对象中的 user 属性中。


1.修改 ordercustom-mapper.xml
定义 resultMap


<?xml version="1.0" encoding="utf-8" ?>
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">






















2.新增一个接口
OrderCustomMapper.java


/**
*@Description : mapper 接口
*/
public interface OrderCustomMapper {
OrderCustom findOrdersUserByResultType() throws Exception;
List findOrdersUserByResultMap() throws Exception;
}

3.测试



···
@Test
public void testOne2OneByResultMap(){
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建usermapper对象,mybatis自动生成代理对象
OrderCustomMapper orderCustomMapper = sqlSession.getMapper(OrderCustomMapper.class);
//调用UserMapper的方法
List orderList = null;
try {
orderList = orderCustomMapper.findOrdersUserByResultMap();
System.out.println(orderList);
} catch (Exception e) {
e.printStackTrace();
}
}一对多查询

需求:查询订单及订单明细


使用sql 实现业务:


SELECT c.username,c.sex,c.address,a.*,b.id as orderdetailId,b.item_id as itemId,b.count
FROM tb_orders a
LEFT JOIN tb_orderdetail b on a.id = b.order_id
LEFT JOIN tb_user c on a.userId = c.id;使用 resultType

分析:
如果使用 resultType 将查询结果映射到 pojo 中,订单信息就会重复。


使用 resultMap

预期:
对 order 的映射不能出现重复记录。
在 Order 中添加 一个 Orderdetail 的 List 属性,将查询结果中的订单信息映射到 Order 中,订单明细信息映射到 List 中,这样订单信息就不会重复。


1.修改 ordercustom-mapper.xml
定义 resultMap


<?xml version="1.0" encoding="utf-8" ?>
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">





































2.新增一个接口


OrderCustomMapper.java


/**
*@Description : mapper 接口
*/
public interface OrderCustomMapper {
OrderCustom findOrdersUserByResultType() throws Exception;
List findOrdersUserByResultMap() throws Exception;
List findAllOrdersAndOrderdetails() throws Exception;
}

3.测试



···
@Test
public void testOne2MoreByResultMap(){
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建usermapper对象,mybatis自动生成代理对象
OrderCustomMapper orderCustomMapper = sqlSession.getMapper(OrderCustomMapper.class);
//调用UserMapper的方法
List orderList = null;
try {
orderList = orderCustomMapper.findOrdersUserByResultMap();
System.out.println(orderList);
} catch (Exception e) {
e.printStackTrace();
}
}多对多查询

需求:查询用户及用户购买的商品信息


sql 实现业务:


SELECT c.username,c.sex,c.address,a.*,b.id as orderdetailId,b.order_id as orderId ,b.item_id as itemId,b.count as count,d.`name` as itemName,d.price as itemPrice,d.detail as itemDetail
FROM tb_orders a
LEFT JOIN tb_orderdetail b on a.id = b.order_id
LEFT JOIN tb_user c on a.userId = c.id
LEFT JOIN tb_items d on b.item_id = d.id;

映射思路:
用户信息映射到 User 中,
在 User 中添加 List 属性,用于映射用户下的订单
Order 中的 List 用于映射 Order 对应的订单明细
Orderdetail 中添加 Item 属性用于映射明细对应商品的信息


1.pojo 类


User.java


public class User {
//user 基本属性
···
private List orders;

//setter and getter and toString
···
}

Order.java


public class Order {
//Order 基本属性
···
//订单明细
private List orderdetails;

//setter and getter and toString
···
}

Orderdetail.java


public class Orderdetail {
//Orderdetail 基本属性
···
//明细对应的商品信息
private Item items;

//setter and getter and toString
···
}

2.映射文件


userorders-mapper.xml


<?xml version="1.0" encoding="utf-8" ?>
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

































加载映射文件:
mybatis-config.xml


<?xml version="1.0" encoding="UTF-8" ?>
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
















···



2.接口定义
UserOrdersMapper.java


import java.util.List;
/用户及所下订单信息查询接口
public interface UserOrdersMapper {
List findUserAndOrdersByUserId(int userid) throwsException;
}

3.测试


···
@Test
public void testMore2MoreByResultMap(){
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建usermapper对象,mybatis自动生成代理对象
UserOrdersMapper userOrdersMapper = sqlSession.getMapper(UserOrdersMapper.class);
//调用UserMapper的方法
List users = null;
try {
users = userOrdersMapper.findUserAndOrdersByUserId(1);
System.out.println(users);
} catch (Exception e) {
e.printStackTrace();
}
}
结果集映射总结

resultType
按照sql 查询结果的字段名(column)与 resultType 定义的 pojo 类的属性名一对一映射,完成映射。
通常用于简单的不包含表连接关系的结果映射。

resultMap
需要完成一对一,一对多,多对多这些特殊的包含表连接关系的复杂结果映射。

association
将一对一的关联查询信息映射到 pojo 中,使用 resultType 无法完成成员属性为对象的自动映射。
例:订单 pojo 中包含一个 User 对象,使用 resultType 无法将 sql 的查询结果中的 User 信息自动映射到 User 成员变量中。

collection
将一对多的关联查询信息映射到一个 List 集合中


使用 resultMap 能对复杂的查询结果集进行面向对象设计,而且可以通过成员变量的形式,大大减少 pojo 类的创建,同时也可以减少冗余信息的存储,方便对结果集进行遍历查询。





参考链接:
http://blog.csdn.net/column/details/13905.html

分享给朋友:
您可能感兴趣的文章:
随机阅读: