mybatis动态代理实现高级映射,主要整合了mybatis和mysql间的复杂查询方法。在本项目中主要在用户,订单,订单明细,商品明细间进行关联查询操作来理解高级映射。
以下一对一查询,一对多查询,多对多查询三种查询方法主要以resultType(对结果没有特殊的映射要求)和resultMap(对结果有特殊的映射要求)两种封装方法完成。如果对结果没有特殊的映射要求建议使用resultType,但resultMap 可以实现延迟加载, resultType 无法实现延迟加载。
工程结构搭建
- 在工程src下创建一个总包cn.mybatis.xhchen
- 在总包下创建两个包,cn.mybatis.xhchen.entity实体类包和cn.mybatis.xhchen.mapper接口mapper包
- 工程下创建config文件集与src同级
- Config下创建mapper包,数据源文件db.properties,日志文件log4j.properties和mybatis的核心配置文件SqlMapConfig.xml
工程环境搭建
Jar包
db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8
jdbc.username=root
jdbc.password=root
log4j.properties
# Global logging configuration
log4j.rootLogger=DEBUG, stdout
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
SqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 加载db.properties配置 -->
<properties resource="db.properties"></properties>
<!-- 和spring整合后 environments配置将废除 -->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事务管理 -->
<transactionManager type="JDBC" />
<!-- 数据库连接池 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<!-- 加载映射文件 -->
<mappers>
<!-- 动态代理数据库操作配置文件 -->
<mapper resource="mapper/ordersMapper.xml"/>
</mappers>
</configuration>
工程编写
一对一查询
将查询结果映射到pojo封装,为了更好的了解和区别两种方法,在一对一查询中用了两种封装方法进行查询 。
项目用到的需求:查询订单信息,关联查询用户信息
- resultType的封装方法查询
实现较为简单,如果 pojo 中没有包括查询出来的列名,需要增加列名对应的属性,即可完成映射。
映射思路
在Orders.java中添加用户信息字段private Customer customer; 并生成getter/setter。最终会将订单信息映射到 orders 中,订单所对应的用户信息映射到 orders 中的 customer属性中。
在cn.mybatis.xhchen.entity下创建订单类Orders.java及其拓展类OrdersCustomer.java,用户类Customer.java
Orders.java
package cn.mybatis.xhchen.entity;
import java.util.Date;
import java.util.List;
/**
*
* ClassName: Orders
*
* @Description: 订单实体类
* @author XHChen
* @date 2018年10月12日 下午2:29:25
*/
public class Orders {
private Integer id; // 订单Id
private Integer user_id; // 下单用户id
private String number; // 订单号
private Date createtime; // 创建订单时间
private String note; // 备注
private Customer customer; // 用户信息
private List<OrderDetail> orderDetail; // 订单明细
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getUser_id() {
return user_id;
}
public void setUser_id(Integer user_id) {
this.user_id = user_id;
}
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;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public List<OrderDetail> getOrderDetail() {
return orderDetail;
}
public void setOrderDetail(List<OrderDetail> orderDetail) {
this.orderDetail = orderDetail;
}
@Override
public String toString() {
return "Orders [id=" + id + ", user_id=" + user_id + ", number="
+ number + ", createtime=" + createtime + ", note=" + note
+ ", customer=" + customer + ", orderDetail=" + orderDetail
+ "]";
}
}
OrdersCustomer.java
package cn.mybatis.xhchen.entity;
/**
*
* ClassName: OrdersCustom
*
* @Description: Custom的拓展类
* @author XHChen
* @date 2018年10月12日 下午2:29:44
*/
public class OrdersCustom extends Orders {
// 添加用户其他的属性
}
Customer.java
package cn.mybatis.xhchen.entity;
import java.util.List;
/**
*
* ClassName: Customer
*
* @Description: 用户信息
* @author XHChen
* @date 2018年10月12日 下午2:34:13
*/
public class Customer {
private Integer id; // 用户id
private String username; // 用户名称
private String sex; // 用户性别
private String address; // 用户地址
private List<Orders> orderslist; // 订单列表
public List<Orders> getOrderslist() {
return orderslist;
}
public void setOrderslist(List<Orders> orderslist) {
this.orderslist = orderslist;
}
public Integer getId() {
return id;
}
public void setId(Integer 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 String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Customer [id=" + id + ", username=" + username + ", sex=" + sex
+ ", address=" + address + ", orderslist=" + orderslist + "]";
}
}
在/config/mapper下创建sql编写文件ordersMapper.xml 编写sql语句
<?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="cn.mybatis.xhchen.mapper.OrdersCustomMapper">
<!-- 一对一查询 -->
<!-- 查询订单,关联查询用户信息,使用resultType实现 -->
<select id="findOrderCustomerResultType" resultType="cn.mybatis.xhchen.entity.OrdersCustom">
SELECT
orders.*,
customer.username,
customer.sex,
customer.address
FROM
orders,
customer
WHERE
orders.user_id=customer.id
</select>
</mapper>
在cn.mybatis.xhchen.mapper下编写OrdersCustomMapper.java接口方法(后面只提供方法内容)
package cn.mybatis.xhchen.mapper;
import java.util.List;
import cn.mybatis.xhchen.entity.Customer;
import cn.mybatis.xhchen.entity.Orders;
import cn.mybatis.xhchen.entity.OrdersCustom;
/**
*
* ClassName: OrdersCustomMapper
*
* @Description: 查询订单
* @author XHChen
* @date 2018年10月12日 下午2:26:05
*/
public interface OrdersCustomMapper {
// 一对一查询订单,关联查询用户信息,resultType实现
public List<OrdersCustom> findOrderCustomerResultType() throws Exception;
}
编写Junit Test Case测试类方法(后面测试只提供方法内容)
package cn.mybatis.xhchen.mapper;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
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 cn.mybatis.xhchen.entity.Customer;
import cn.mybatis.xhchen.entity.Orders;
import cn.mybatis.xhchen.entity.OrdersCustom;
public class OrdersCustomMapperTest {
// 创建会话工厂
private SqlSessionFactory sqlSessionFactory;
@Before
/**
*
* @Description: 加载mapper
* @param @throws IOException
* @return void
* @throws
* @author XHChen
* @date 2018年10月12日 下午2:40:23
*/
public void setUp() throws IOException {
// 定义核心配置文件
String resource = "SqlMapConfig.xml";
// 获得核心配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建会话工厂,加载配置文件流
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
/**
*
* @Description: 一对一查询订单,关联查询用户信息,ResultType实现
* @param @throws Exception
* @return void
* @throws
* @author XHChen
* @date 2018年10月12日 下午3:02:42
*/
public void testfindOrderCustomerResultType() throws Exception {
// 开启sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 动态代理
OrdersCustomMapper ordersCustomMapper = sqlSession.getMapper(OrdersCustomMapper.class);
List<OrdersCustom> list = ordersCustomMapper.findOrderCustomerResultType();
// 遍历结果
for (OrdersCustom ordersCustom : list) {
System.out.println(ordersCustom);
}
System.out.println(list.size());
sqlSession.close();
}
}
2.resultMap的封装方法查询
如果对查询结果有特殊的要求,使用 resultMap 可以完成将关联查询映射 pojo 的属性中.
在/config/mapper下创建sql编写文件ordersMapper.xml 编写sql语句
注意:<select>标签中的resultMap与<resultMap>标签中的id保持一致
<resultMap type="cn.mybatis.xhchen.entity.Orders" id="OrdersCustomerResultMap">
<!-- 配置映射的订单信息 -->
<!-- id:查询列中的唯一标识,订单信息中的唯一标识 column:订单信息的唯一标识 列 property:订单信息的唯一标识列所映射到orders中的那个属性 -->
<id column="id" property="id" />
<result column="user_id" property="user_id" />
<result column="number" property="number" />
<result column="createtime" property="createtime" />
<result column="note" property="note" />
<!-- 配置映射的关联用户信息 -->
<!--association:用于映射关联查询单个对象的信息 property:要将关联查询的用户信息映射到Orders中那个属性 -->
<association property="customer" javaType="cn.mybatis.xhchen.entity.Customer">
<!-- id:关联查询用户的唯一标识 column:指定唯一标识用户信息的列 property:映射到user的那个属性 -->
<id column="id" property="id" />
<result column="username" property="username" />
<result column="sex" property="sex" />
<result column="address" property="address" />
</association>
</resultMap>
<!-- 查询订单,关联查询用户信息,使用resultMap实现 -->
<select id="findOrderCustomerResultMap" resultMap="OrdersCustomerResultMap">
SELECT
orders.*,
customer.username,
customer.sex,
customer.address
FROM
orders,
customer
WHERE
orders.user_id=customer.id
</select>
在cn.mybatis.xhchen.mapper下编写OrdersCustomMapper.java接口方法
// 一对一查询订单,关联查询用户信息,ResultMap实现
public List<Orders> findOrderCustomerResultMap() throws Exception;
编写Junit Test Case测试类方法
@Test
/**
*
* @Description: 一对一查询订单,关联查询用户信息,ResultMap实现
* @param @throws Exception
* @return void
* @throws
* @author XHChen
* @date 2018年10月12日 下午3:22:30
*/
public void testfindOrderCustomerResultMap() throws Exception {
// 开启sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 动态代理
OrdersCustomMapper ordersCustomMapper = sqlSession.getMapper(OrdersCustomMapper.class);
List<Orders> list = ordersCustomMapper.findOrderCustomerResultMap();
// 遍历结果
for (Orders orders : list) {
System.out.println(orders);
}
System.out.println(list.size());
sqlSession.close();
}
一对多查询
使用 association将关联查询信息映射到一个pojo对象中 和 collection将关联查询信息映射到一个list集合中 完成一对多高级映射
项目用到的需求:查询订单关联查询用户及订单明细
映射思路
在Orders.java中添加订单明细字段private List<OrderDetail> orderDetail;并生成getter/setter。最终会将订单信息映射到 orders 中,订单所对应的订单明细映射到 orders 中的 orderDetails 属性中。
在cn.mybatis.xhchen.entity下创建订单明细类OrdersDetail.java
package cn.mybatis.xhchen.entity;
/**
*
* ClassName: OrderDetail
*
* @Description: 订单明细
* @author XHChen
* @date 2018年10月12日 下午4:30:50
*/
public class OrderDetail {
private Integer id; // 明细主键id
private Integer items_id; // 明细项目
private Integer items_num; // 明细编号
private Integer orders_id; // 订单id
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 getItems_id() {
return items_id;
}
public void setItems_id(Integer items_id) {
this.items_id = items_id;
}
public Integer getItems_num() {
return items_num;
}
public void setItems_num(Integer items_num) {
this.items_num = items_num;
}
public Integer getOrders_id() {
return orders_id;
}
public void setOrders_id(Integer orders_id) {
this.orders_id = orders_id;
}
@Override
public String toString() {
return "OrderDetail [id=" + id + ", items_id=" + items_id
+ ", items_num=" + items_num + ", orders_id=" + orders_id
+ ", items=" + items + "]";
}
}
在/config/mapper下创建sql编写文件ordersMapper.xml 编写sql语句
注意:<select>标签中的resultMap与<resultMap>标签中的id保持一致
<!-- 一对多查询 -->
<resultMap type="cn.mybatis.xhchen.entity.Orders" id="OrdersAndOrderdetailResultMap" extends="OrdersCustomerResultMap">
<!-- 继承 OrdersCustomerResultMap-->
<!-- 配置映射的订单信息 -->
<!-- 配置映射的关联用户信息 -->
<!-- 关联订单明细信息
一个订单关联查询出了多条订单明细,要使用collection映射
collection:对关联查询到的多条记录映射到集合中
property:将关联查询到的多条记录映射到orders类的那个属性
ofType:指定映射的集合属性中pojo的类型
-->
<collection property="orderDetail" ofType="cn.mybatis.xhchen.entity.OrderDetail">
<!-- id:唯一标识
property:要将订单明细的唯一标识映射到com.mybatis.entity.OrderDetail的那个属性
-->
<id column="id" property="id"/>
<result column="items_id" property="items_id"/>
<result column="items_num" property="items_num"/>
<result column="orders_id" property="orders_id"/>
</collection>
</resultMap>
<!-- 查询订单关联查询用户及订单明细,使用resultMap实现 -->
<select id="findOrdersAndOrderdetailResultMap" resultMap="OrdersAndOrderdetailResultMap">
SELECT orders.*,
customer.username,
customer.sex,
customer.address,
orderdetail.id as orderdetail_id,
orderdetail.items_id,
orderdetail.items_num,
orderdetail.orders_id
FROM
orders,
customer,
orderdetail
WHERE
orders.user_id = customer.id AND orderdetail.orders_id = orders.id
</select>
在cn.mybatis.xhchen.mapper下编写OrdersCustomMapper.java接口方法
// 一对多查询订单关联查询用户及订单明细,使用resultMap实现
public List<Orders> findOrdersAndOrderdetailResultMap() throws Exception;
编写Junit Test Case测试类方法
@Test
/**
*
* @Description: 一对多查询订单关联查询用户及订单明细,使用resultMap实现
* @param
* @return void
* @throws
* @author XHChen
* @date 2018年10月12日 下午5:17:32
*/
public void findOrdersAndOrderdetailResultMap() throws Exception {
// 开启sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 动态代理
OrdersCustomMapper ordersCustomMapper = sqlSession.getMapper(OrdersCustomMapper.class);
List<Orders> list = ordersCustomMapper.findOrdersAndOrderdetailResultMap();
// 遍历
for (Orders orders : list) {
System.out.println(orders);
}
System.out.println(list.size());
sqlSession.close();
}
多对多查询
使用 association将关联查询信息映射到一个pojo对象中 和 collection将关联查询信息映射到一个list集合中 完成一对多高级映射
项目用到的需求:查询用户以及用户购买的商品信息
映射思路
将用户所有信息映射到Customer中。
在Customer中添加订单列表属性private List<Orders> orderslist;,将创建的订单映射到orderslist;
在Orders中添加订单明细属性private List<OrderDetail> orderDetail;,将创建的订单明细映射到orderDetail;
在OrdersDetail中添加商品明细属性private Items items;,将创建的商品信息映射到items。
在/config/mapper下创建sql编写文件ordersMapper.xml 编写sql语句
注意:<select>标签中的resultMap与<resultMap>标签中的id保持一致
<!-- 多对多查询 -->
<resultMap type="cn.mybatis.xhchen.entity.Customer" id="CustomerAndOrderdetailResultMap">
<!-- 用户信息 -->
<id column="id" property="id" />
<result column="username" property="username" />
<result column="sex" property="sex" />
<result column="address" property="address" />
<!-- 订单信息 -->
<collection property="orderslist" ofType="cn.mybatis.xhchen.entity.Orders">
<id column="id" property="id" />
<result column="user_id" property="user_id" />
<result column="number" property="number" />
<result column="createtime" property="createtime" />
<result column="note" property="note" />
<!-- 订单明细信 -->
<collection property="orderDetail" ofType="cn.mybatis.xhchen.entity.OrderDetail">
<id column="id" property="id"/>
<result column="items_id" property="items_id"/>
<result column="items_num" property="items_num"/>
<result column="orders_id" property="orders_id"/>
<!-- 商品信息 -->
<association property="items" javaType="cn.mybatis.xhchen.entity.Items">
<id column="id" property="id"/>
<result column="items_name" property="items_name"/>
<result column="items_detail" property="items_detail"/>
<result column="items_price" property="items_price"/>
</association>
</collection>
</collection>
</resultMap>
<!-- 查询用户以及用户购买的商品信息 -->
<select id="findCustomerAndOrderdetailResultMap" resultMap="CustomerAndOrderdetailResultMap">
SELECT
orders.*,
customer.username,
customer.sex,
customer.address,
orderdetail.id as orderdetail_id,
orderdetail.items_id,
orderdetail.items_num,
orderdetail.orders_id,
items.id as items_id,
items.items_name,
items.items_detail,
items.items_price
FROM
orders,
customer,
orderdetail,
items
WHERE
orders.user_id = customer.id AND orderdetail.orders_id = orders.id AND orderdetail.items_id = items.id
</select>
在cn.mybatis.xhchen.mapper下编写OrdersCustomMapper.java接口方法
// 多对多查询用户以及用户购买的商品信息
public List<Customer> findCustomerAndOrderdetailResultMap() throws Exception;
编写Junit Test Case测试类方法
@Test
/**
*
* @Description: 多对多查询用户以及用户购买的商品信息
* @param
* @return void
* @throws
* @author XHChen
* @date 2018年10月14日 上午10:52:34
*/
public void testfindCustomerAndOrderdetailResultMap() throws Exception {
// 开启sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 加载动态代理
OrdersCustomMapper ordersCustomMapper = sqlSession.getMapper(OrdersCustomMapper.class);
// 查询操作
// 调用mapper方法
List<Customer> list = ordersCustomMapper.findCustomerAndOrderdetailResultMap();
// 遍历结果
for (Customer customer : list) {
System.out.println(customer);
}
System.out.println(list.size());
sqlSession.close();
}