Mybatis关系映射主要是包括一对一,一对多,多对一,和多对多关系。
再进行我们关系映射的时候,我们需要有一个数据模型来模拟我们对应的相应关系,我们采用的数据模型为用户和订单,订单和订单明细,以及商品之间的关系。
用户表user:记录了购买商品的用户信息。
订单表orders:记录了用户所创建的订单(购买商品的订单)。
订单明细表orderdetail:记录了订单的详细信息即购买商品的信息。
商品表items:记录商品信息。
先分析数据级别之间有关系的表之间的业务关系:
usre和orders:
user —-> orders:一个用户可以创建多个订单,一对多
orders —-> user:一个订单只由一个用户创建,一对一
orders和orderdetail:
orders —-> orderdetail:一个订单可以包括 多个订单明细,因为一个订单可以购买多个商品,每个商品的购买信息在orderdetail记录,一对多关系。
orderdetail —-> orders:一个订单明细只能包括在一个订单中,一对一
orderdetail和itesm:
orderdetail —-> itesms:一个订单明细只对应一个商品信息,一对一
items —-> orderdetail:一个商品可以包括在多个订单明细 ,一对多
再分析数据库级别没有关系的表之间是否有业务关系:
orders和items:
orders和items之间可以通过orderdetail表建立 关系。
实例:查询订单信息,关联查询创建订单的用户信息。
SELECT orders.*,user.username,user.sex,user.address FROM orders,USER WHERE orders.user_id = user.id
主查询表:orders
关联查询表:user
联结查询:内联结
1、SQL语句的书写要领:先确定查询的主表,在确定查询的关联表,关联查询是使用内联结还是外联结。
2、POVO扩展类创建。(这是由于关联查询出来的信息是多张表的综合字段,所以我们可以根据POJO创建我们的扩展类)
3、Mapper.xml和Mapper.java的代理编写
4、进行测试
相关代码:
// POJO基础类
public class Orders {
private int id;
private int userid;
// private int user_id;
private String number;
private Date createtime;
private String note;
}
// POVO扩展类 Orders的扩展类,通过此类可以映射订单和用户查询的结果。
public class OrdersExtends extends Orders{
private String username;
private String sex;
private String address;
}
// Mapper.xml配置
<select id="findorderanduser" resultType="com.wf.model.OrdersExtends">
SELECT orders.*,user.username,user.sex,user.address FROM orders,USER WHERE orders.user_id = user.id
select>
//Mapper.java 代理接口
public interface OrdersExtendsMapper {
public List findorderanduser();
}
//测试代码
@Test
public void testOrdersExtendsMapper() {
SqlSession session = sqlsessionfactory.openSession();
OrdersExtendsMapper orderextendsmapper = session.getMapper(OrdersExtendsMapper.class);
List list = orderextendsmapper.findorderanduser();
for(OrdersExtends o :list){ System.out.println(o.getId()+":"+o.getUserid()+":"+o.getUsername()+":"+o.getAddress());
//System.out.println(o.getId()+":"+o.getUser_id()+":"+o.getUsername()+":"+o.getAddress()); //getUserid没有和数据库对应,所以无法获取默认为0
}
}
注意:上述测试代码中,由于userid没有和数据库中的字段进行对应(user_id),所以会造成数据映射不成功而默认为0
思路:利用 ResultMap 有点类似于Hibernate中POJO类中的设置。将我们对应的属性关联到类中。
1、使用resultMap将查询结果中的订单信息映射到Orders对象中,
2、在orders类中添加User属性,将关联查询出来的用户信息映射到orders对象中的user属性中。
// POJO基础类
public class Orders {
private User user; // 在Orders类中配置我们的User属性
private int id;
private int userid;
private String number;
private Date createtime;
private String note;
}
// Mapper.xml
public interface OrdersExtendsMapper {
public List<Orders> findorderanduserResultMap();
}
// Mapper.java
<mapper namespace="com.wf.dao.OrdersExtendsMapper">
<resultMap type="com.wf.model.Orders" id="OrderUserResultMap">
<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="user" javaType="com.wf.model.User">
<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="findorderanduserResultMap" resultMap="OrderUserResultMap">
SELECT orders.*,user.username,user.sex,user.address FROM orders,USER WHERE
orders.user_id = user.id
select>
mapper>
说明:
利用 ResultMap,我们可以利用其中的association 属性将外键关联的相关类进行映射。这也是使用ResultMap 的便利之一。
1、resultType:使用resultType实现较为简单,如果pojo中没有包括查询出来的列名,需要增加列名对应的属性,即可完成映射。如果没有查询结果的特殊要求建议使用resultType。
2、resultMap:需要单独定义resultMap,实现有点麻烦,如果对查询结果有特殊的要求,使用resultMap可以完成将关联查询映射pojo的属性中。
3、resultMap可以实现延迟加载,resultType无法实现延迟加载。
实例:查询订单及订单明细的信息。
SELECT orders.*,
user.username,user.sex,user.address ,
orderdetail.id,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
主查询表:orders
确定关联查询表:orderdetail
联结查询:内联结
利用resultType将上边的 查询结果映射到pojo中,订单信息的就是重复。而我们对于对orders映射不能出现重复记录。所以我们这里只能利用ResultMap。
// POJO类
public class User {
private int id;
private String username;
private Date birthday;
private String address;
private String sex;
}
public class Orders {
private User user;
private int id;
private int userid;
private String number;
private Date createtime;
private String note;
private List orderdetails; // 一对多关系设置
}
public class OrdersDetail {
private int id;
private int ordersId;
private int itemsId;
private int itemsNum;
}
//Mapper.java
public interface OrdersExtendsMapper {
// 查询订单(关联用户)订单明细
public List findOrderAndDetailResultMap();
}
//Mapper.xml
"com.wf.model.Orders" id="findOrderAndDetailResultMap" >
"id" property="id"/>
"user_id" property="userid"/>
"number" property="number"/>
"createtime" property="createtime"/>
"note" property="note"/>
"user" javaType="com.wf.model.User">
"user_id" property="id"/>
"username" property="username"/>
"sex" property="sex"/>
"address" property="address"/>
"orderdetails" ofType="com.wf.model.OrdersDetail">
"orderdetail_id" property="id"/>
"items_id" property="itemsId"/>
"items_num" property="itemsNum"/>
"orders_id" property="ordersId"/>
// 测试代码
@Test
public void testfindOrderAndDetailResultMap() {
SqlSession session = sqlsessionfactory.openSession();
OrdersExtendsMapper orderextendsmapper = session.getMapper(OrdersExtendsMapper.class);
List list = orderextendsmapper.findOrderAndDetailResultMap();
// 断点查看,打印查询4条,list存储2条,自动去重了
for(Orders o :list){
System.out.println(o.getId()+":"+o.getUser().getId()+":"+o.getUser().getUsername()+":"+o.getUser().getAddress());
}
}
注意:对于一对多或者多对一的查询,建议使用ResultMap映射进行代码编写,
mybatis使用resultMap的collection对关联查询的多条记录映射到一个list集合属性中。
使用resultType实现:
将订单明细映射到orders中的orderdetails中,需要自己处理,使用双重循环遍历,去掉重复记录,将订单明细放在orderdetails中。
实例:查询用户及用户购买商品信息。
查询主表是:user
关联表:由于用户和商品没有直接关联,通过订单和订单明细进行关联,所以关联表:
orders、orderdetail、items
联结查询:内联结
// POJO类
public class User {
private int id;
private String username;
private Date birthday;
private String address;
private String sex;
private List orderslist; //一对多
}
public class Orders {
private User user; // 用户信息
private int id;
private int userid;
private String number;
private Date createtime;
private String note;
private List orderdetails; //商品信息存放集合
}
public class OrdersDetail {
private int id;
private int ordersId;
private int itemsId;
private int itemsNum;
private Items items; //商品信息
}
public class Items {
private int id;
private String name;
private double price;
private String detail;
private String pic;
private Date createtime;
}
// Mapper.java
public interface OrdersExtendsMapper {
public List findUserAndItemResultMap();
}
//Mapper.xml
"com.wf.model.User" id="UserAndItemResultMap">
"user_id" property="id"/>
"username" property="username"/>
"sex" property="sex"/>
"address" property="address"/>
"orderslist" ofType="com.wf.model.Orders">
"id" property="id"/>
"user_id" property="userid"/>
"number" property="number"/>
"createtime" property="createtime"/>
"note" property="note"/>
"orderdetails" ofType="com.wf.model.OrdersDetail">
"orderdetail_id" property="id"/>
"items_id" property="itemsId"/>
"items_num" property="itemsNum"/>
"orders_id" property="ordersId"/>
"items" javaType="com.wf.model.Items">
"items_id" property="id"/>
"items_name" property="name"/>
"item_price" property="price"/>
"item_datail" property="detail"/>
//测试代码
@Test
public void testfindUserAndItemResultMap() {
SqlSession session = sqlsessionfactory.openSession();
OrdersExtendsMapper orderextendsmapper = session.getMapper(OrdersExtendsMapper.class);
List list = orderextendsmapper.findUserAndItemResultMap();
for(User o :list){
System.out.println(o.getId()+":"+o.getUsername()+":"+o.getAddress()
+":"+o.getOrderslist().get(0).getOrderdetails().get(0).getItems().getName());
}
}
注意:我们在利用多对多的情况下,一定要主要ResultMap的嵌套关系。