一、一对一关系映射

使用resultType+包装类实现

  1、假设问题背景是要求在某一个购物平台的后台程序中添加一个这样的功能:查询某个订单的信息和下该订单的用户信息。首先我们可以知道,一般这样的平台上面,某一笔订单只属于某一个用户,从这个角度来看,可以作为一对一的参考模型

  ①首先创建数据表user(用户表)

CREATE TABLE `user` (
`uid` INT(11) NOT NULL AUTO_INCREMENT,
`username` VARCHAR(255) DEFAULT NULL,
`password` VARCHAR(255) DEFAULT NULL,
`sex` VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (`uid`)
) ENGINE=INNODB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8

  创建orders表(所用的订单表)

CREATE TABLE `orders` (
`oid` INT(11) NOT NULL AUTO_INCREMENT,
`total` DOUBLE DEFAULT NULL,
`ordertime` DATETIME DEFAULT NULL,
`name` VARCHAR(20) DEFAULT NULL,
`uid` INT(11) DEFAULT NULL,
PRIMARY KEY (`oid`),
KEY `FKC3DF62E5AA3D9C7` (`uid`),
CONSTRAINT `FKC3DF62E5AA3D9C7` FOREIGN KEY (`uid`) REFERENCES `user` (`uid`)
) ENGINE=INNODB AUTO_INCREMENT=9004 DEFAULT CHARSET=utf8

  如下图所示:

  ②创建User和Order的实体类

 package cn.mybatis.po;

 public class User {
private int uid;
private String username;
private String password;
private String address;
private String sex; public int getUid() {
return uid;
} public void setUid(int uid) {
this.uid = uid;
} public String getUsername() {
return username;
} public String getPassword() {
return password;
} public String getAddress() {
return address;
} public String getSex() {
return sex;
} public void setUsername(String username) {
this.username = username;
} public void setPassword(String password) {
this.password = password;
} public void setAddress(String address) {
this.address = address;
} public void setSex(String sex) {
this.sex = sex;
} public User(String username, String password, String address, String sex) {
this.username = username;
this.password = password;
this.address = address;
this.sex = sex;
} public User() {
} @Override
public String toString() {
return "User{" +
"uid=" + uid +
", username='" + username + '\'' +
", password='" + password + '\'' +
", address='" + address + '\'' +
", sex='" + sex + '\'' +
'}';
}
}

User类

 package cn.mybatis.po;

 import java.util.Date;

 public class Order {

     private int oid;
private double total;
private Date ordettime;
private String name; public int getOid() {
return oid;
} public void setOid(int oid) {
this.oid = oid;
} public double getTotal() {
return total;
} public void setTotal(double total) {
this.total = total;
} public Date getOrdettime() {
return ordettime;
} public void setOrdettime(Date ordettime) {
this.ordettime = ordettime;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @Override
public String toString() {
return "Order{" +
"oid=" + oid +
", total=" + total +
", ordettime=" + ordettime +
", name='" + name + '\'' +
'}';
}
}

Order类

  ③用于需要同时查询User和Order的信息,所以需要用到上一篇中讲到的POJO输出映射类型。具体来说就是,需要自定义一个OrderPoJo,其中包含我们要查询的Order和User信息,定义的OrderPoJo类型如下(这里我们可以使用继承的方式,如果我们查询结果中哪一个类的要查询结果多就继承该类,可以简便包装类的编写)

 package cn.mybatis.po;

 public class OrderPoJo extends Order{

     private String username;
private String address;
private String sex; public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String getAddress() {
return address;
} public void setAddress(String address) {
this.address = address;
} public String getSex() {
return sex;
} public void setSex(String sex) {
this.sex = sex;
} @Override
public String toString() {
return "OrderPoJo{" +
super.toString() +
"username='" + username + '\'' +
", address='" + address + '\'' +
", sex='" + sex + '\'' +
'}';
}
}

  ④编写好对应的实体类和包装类之后就开始写,mapper配置文件和mapper.java。mapper配置文件中我们只需要根据问题背景写好相应的Sql语句就好

  这是编写好Sql的Mapper配置文件

 <?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指定了命名空间-->
<mapper namespace="cn.mybatis.mapper.OrderMapper"> <select id="findOrderAndUser" parameterType="int" resultType="orderPoJo">
SELECT orders.*,
user.username,user.sex,user.address
FROM orders,USER
WHERE oid = #{id} AND user.uid = orders.uid
</select> </mapper>

  下面是mapper接口中的一个方法,由于我们只需要完成这一个问题,所以OrderMapper接口也比较简单

  

  ⑤编写好所有的文件后,使用Junit来测试文件

 package cn.mybatis.mapper;

 import cn.mybatis.po.OrderPoJo;
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; public class OrderMapperTest { private SqlSessionFactory sqlSessionFactory; @Before
public void setUp() throws Exception {
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} @Test
public void testFindOrderAndUser() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class); OrderPoJo orderPoJo = orderMapper.findOrderAndUser(3); System.out.println(orderPoJo); sqlSession.close(); } }

  ⑥我们来通过日志分析一下结果:最终能够按照既定的Sql查询出响应的结果

使用resultMap在配置文件中实现

  1、我们使用resultMap来进行测试的时候,首先需要注意的是,由于没有自定义包装类型,所以需要在原始的Order中添加User类型的属性,保证可以在Mapper配置文件中将查询到的User属性配置到user中,从而得到关联查询结果

 package cn.mybatis.po;

 import java.util.Date;

 public class Order {

     private int oid;
private double total;
private Date ordertime;
private String name;
private User user; public int getOid() {
return oid;
} public void setOid(int oid) {
this.oid = oid;
} public double getTotal() {
return total;
} public void setTotal(double total) {
this.total = total;
} public Date getOrdertime() {
return ordertime;
} public void setOrdertime(Date ordertime) {
this.ordertime = ordertime;
} public String getName() {
return name;
} public User getUser() {
return user;
} public void setUser(User user) {
this.user = user;
} public void setName(String name) {
this.name = name;
} @Override
public String toString() {
return "Order{" +
"oid=" + oid +
", total=" + total +
", ordertime=" + ordertime +
", name='" + name + '\'' +
", user=" + user +
'}';
}
}

  2、相关类和上面的内容一样,我们使用resultMap来实现,显然需要在Mapper中配置resultMap

     <!--
订单关联User的查询resultMap
将查询的结果全部映射到Order类中
-->
<resultMap id="OrderResultMap" type="cn.mybatis.po.Order">
<!--配置映射订单-->
<id column="oid" property="oid"></id>
<result column="total" property="total"></result>
<result column="ordertime" property="ordertime"></result>
<result column="name" property="name"></result> <!--配置关联用户信息-->
<!--
association:用于映射关联查询单个对象的信息
property:用于设置将关联信息映射到Order的哪个属性中
-->
<association property="user" javaType="cn.mybatis.po.User">
<id column="uid" property="uid"></id>
<result column="username" property="username"></result>
<result column="address" property="address"></result>
<result column="sex" property="sex"></result>
</association>
</resultMap>

  3、然后在Mapper配置文件中使用resultMap类型的statment

    <select id="findOrderAndUserByResultMap" parameterType="int" resultMap="OrderResultMap">
SELECT orders.*,
user.username,user.sex,user.address
FROM orders,USER
WHERE oid = #{id} AND user.uid = orders.uid
</select>

  4、结果同使用resultType的结果一样

二、一对多关系映射

   1、我们先分析一下orderitem和orders两张数据表的关系,我们能够想到一条订单中包含许多详细的订单条目信息,所以简单的得到下面的关系

  

  2、在上面的基础上,我们再创建一张orderitem数据表

CREATE TABLE `orderitem` (
`itemid` INT(11) NOT NULL AUTO_INCREMENT,
`count` INT(11) DEFAULT NULL,
`subtotal` DOUBLE DEFAULT NULL,
`pid` INT(11) DEFAULT NULL,
`oid` INT(11) DEFAULT NULL,
PRIMARY KEY (`itemid`),
KEY (`oid`),
KEY (`pid`),
KEY (`oid`),
FOREIGN KEY (`oid`) REFERENCES `orders` (`oid`),
FOREIGN KEY (`pid`) REFERENCES `product` (`pid`)
) ENGINE=INNODB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8

  3、我们再创建相应的实体类orderitem

 package cn.mybatis.po;

 public class OrderItem {

     private int itemid;
private int count;
private double subtotal;
private int pid; public int getItemid() {
return itemid;
} public void setItemid(int itemid) {
this.itemid = itemid;
} public int getCount() {
return count;
} public void setCount(int count) {
this.count = count;
} public double getSubtotal() {
return subtotal;
} public void setSubtotal(double subtotal) {
this.subtotal = subtotal;
} public int getPid() {
return pid;
} public void setPid(int pid) {
this.pid = pid;
} @Override
public String toString() {
return "OrderItem{" +
"itemid=" + itemid +
", count=" + count +
", subtotal=" + subtotal +
", pid=" + pid +
'}';
}
}

orderitem实体类

  4、类似于上面讲到的使用resultMap的方式,我们在Order中添加上orderitem这一属性,作用就是维护Order和Orderitem的关联关系

 package cn.mybatis.po;

 import java.util.Date;
import java.util.List; public class Order { private int oid;
private double total;
private Date ordertime;
private String name;
private User user; private List<OrderItem> orderItems; public int getOid() {
return oid;
} public void setOid(int oid) {
this.oid = oid;
} public double getTotal() {
return total;
} public void setTotal(double total) {
this.total = total;
} public Date getOrdertime() {
return ordertime;
} public void setOrdertime(Date ordertime) {
this.ordertime = ordertime;
} public String getName() {
return name;
} public User getUser() {
return user;
} public void setUser(User user) {
this.user = user;
} public void setName(String name) {
this.name = name;
} public List<OrderItem> getOrderItems() {
return orderItems;
} public void setOrderItems(List<OrderItem> orderItems) {
this.orderItems = orderItems;
} @Override
public String toString() {
return "Order{" +
"oid=" + oid +
", total=" + total +
", ordertime=" + ordertime +
", name='" + name + '\'' +
", user=" + user +
", orderItems=" + orderItems +
'}';
}
}

修改后的Order类

  5、我们先配置Mapper文件。使用collection配置实体类中的List属性(List<OrderItem>)

    <!--查询Order和OrderItem的配置(一对多关系查询配置)-->
<resultMap id="OrderAndOrderItemByResultMap" type="cn.mybatis.po.Order" extends="OrderResultMap">
<!--使用extends,可以将某一段resultMap继承过来-->
<!--OrderItem信息-->
<!--collections:将查询到的多条信息映射到集合中
property:将查询到的多条记录映射到Order中的相应属性中(orderItems)
ofType:指的是要映射的集合中的JavaType-->
<collection property="orderItems" ofType="cn.mybatis.po.OrderItem">
<id column="itemid" property="itemid"></id>
<result column="count" property="count"></result>
<result column="subtotal" property="subtotal"></result>
</collection>
</resultMap>

  6、然后将上面配置的resultMap加入到statment中

    <select id="findOrderAndOrderItemByResultMap" parameterType="int" resultMap="OrderAndOrderItemByResultMap">
SELECT orders.*,
user.username,
user.sex,
user.address,
orderitem.itemid,
orderitem.count,
orderitem.subtotal
FROM
orders,
USER,
orderitem
WHERE orders.oid = #{id} AND user.uid = orders.uid AND orderitem.oid = orders.oid
</select>

  7、然后在Mapper接口中添加测试方法

    //一对多关系测试
public Order findOrderAndOrderItemByResultMap(int id) throws Exception;

  8、将查询的结果进行输出可以发现能够正常查询出想要的结果

Order{oid=2, total=32.0, ordertime=Thu Dec 26 21:47:04 CST 2019, name='Lucy', user=User{uid=2, username='Rose', password='null', address='武汉市', sex='women'}, orderItems=[OrderItem{itemid=2, count=21, subtotal=32.0, pid=0}, OrderItem{itemid=4, count=32, subtotal=54.0, pid=0}]}

 三、多对多关系映射

  1、问题背景就是查询User所购买的商品详细信息,即查询结果包括User信息和Product信息。我们先分析一下整个数据表之间的关系如下图所示

  

  2、在上面分析的基础上,我们创建Product数据表的对应的Product实体类

CREATE TABLE `product` (
`pid` INT(11) NOT NULL AUTO_INCREMENT,
`pname` VARCHAR(255) DEFAULT NULL,
`shop_price` DOUBLE DEFAULT NULL,
PRIMARY KEY (`pid`)
) ENGINE=INNODB AUTO_INCREMENT=80 DEFAULT CHARSET=utf8
 package cn.mybatis.po;

 public class Product {
private int pid;
private String pname;
private double shop_price; public int getPid() {
return pid;
} public void setPid(int pid) {
this.pid = pid;
} public String getPname() {
return pname;
} public void setPname(String pname) {
this.pname = pname;
} public double getShop_price() {
return shop_price;
} public void setShop_price(double shop_price) {
this.shop_price = shop_price;
} @Override
public String toString() {
return "Product{" +
"pid=" + pid +
", pname='" + pname + '\'' +
", shop_price=" + shop_price +
'}';
}
}

Product实体类

  3、一般编写Mapper配置文件可以使用resultMap或者resultType(+自定义扩展类型)来实现,这里,我们使用resultMap在Mapper配置文件中进行,所以需要在OrderItem类中添加Product类型的属性,修改后的OrderItem类如下

 package cn.mybatis.po;

 public class OrderItem {

     private int itemid;
private int count;
private double subtotal; private Product product; public int getItemid() {
return itemid;
} public void setItemid(int itemid) {
this.itemid = itemid;
} public int getCount() {
return count;
} public void setCount(int count) {
this.count = count;
} public double getSubtotal() {
return subtotal;
} public void setSubtotal(double subtotal) {
this.subtotal = subtotal;
} public Product getProduct() {
return product;
} public void setProduct(Product product) {
this.product = product;
} @Override
public String toString() {
return "OrderItem{" +
"itemid=" + itemid +
", count=" + count +
", subtotal=" + subtotal +
", product=" + product +
'}';
}
}

修改的OrderItem类

  4、修改相应的实体类后,可以再Mapper配置文件中配置查询结果User信息以及关联的Order、OrderItem和所要的Product信息,配置如下

    <!--查询User和Product关系结果(多对多关系)-->
<resultMap id="UserAndProductResultMap" type="cn.mybatis.po.User">
<!--User信息-->
<id column="uid" property="uid"></id>
<result column="username" property="username"></result>
<result column="address" property="address"></result>
<result column="sex" property="sex"></result>
<!--Order信息-->
<collection property="orders" ofType="cn.mybatis.po.Order">
<id column="oid" property="oid"></id>
<result column="total" property="total"></result>
<result column="ordertime" property="ordertime"></result>
<result column="name" property="name"></result> <!--OrderItem信息-->
<collection property="orderItems" ofType="cn.mybatis.po.OrderItem">
<id column="itemid" property="itemid"></id>
<result column="count" property="count"></result>
<result column="subtotal" property="subtotal"></result> <association property="product" javaType="cn.mybatis.po.Product">
<id column="pid" property="pid"></id>
<result column="pname" property="pname"></result>
<result column="shop_price" property="shop_price"></result>
</association>
</collection>
</collection>
</resultMap>

  5、然后编写响应的Sql,并添加到Mapper中的statment中

    <select id="findUsersAndProduct" parameterType="int" resultMap="UserAndProductResultMap">
SELECT orders.*,
user.username,
user.sex,
user.address,
orderitem.itemid,
orderitem.count,
orderitem.subtotal,
product.pid,
product.pname,
product.shop_price
FROM
orders,
USER,
orderitem,
product
WHERE user.uid = orders.uid AND orderitem.oid = orders.oid
</select>

  6、在Mapper.java中添加响应的方法

    public List<User> findUsersAndProduct() throws Exception;

  7、最后使用Junit测试结果如下

Mybatis关系映射的更多相关文章

  1. MyBatis 关系映射XML配置

    关系映射 在我看来这些实体类就没啥太大关联关系,不就是一个sql语句解决的问题,直接多表查询就完事,程序将它设置关联就好 xml里面配置也是配置了sql语句,下面给出几个关系的小毛驴(xml) 一对多 ...

  2. (四)MyBatis关系映射

    第一节:一对一关系实现 需要实现一对一的关系,首先我们有两张表,t-addree和t_student. CREATE TABLE `t_address` ( `id` ) NOT NULL AUTO_ ...

  3. mybatis 关系映射

    一:订单商品数据模型 1.数据库执行脚本 创建数据库表代码: 1 CREATE TABLE items ( 2 id INT NOT NULL AUTO_INCREMENT, 3 itemsname ...

  4. mybatis关系映射之一对多和多对一

    本实例使用用户(User)和博客(Post)的例子做说明: 一个用户可以有多个博客, 一个博客只对应一个用户 一. 例子(本实体采用maven构建): 1. 代码结构图: 2. 数据库: t_user ...

  5. Mybatis框架中实现双向一对多关系映射

    学习过Hibernate框架的伙伴们很容易就能简单的配置各种映射关系(Hibernate框架的映射关系在我的blogs中也有详细的讲解),但是在Mybatis框架中我们又如何去实现 一对多的关系映射呢 ...

  6. MyBatis框架——关系映射(一对多、多对多、多对一查询)

    关系映射 一.映射(多)对一.(一)对一的关联关系 1).使用列的别名 ①.若不关联数据表,则可以得到关联对象的id属性 ②.若还希望得到关联对象的其它属性.则必须关联其它的数据表 1.创建表: 员工 ...

  7. Java基础-SSM之mybatis一对多和多对一关系映射

    Java基础-SSM之mybatis一对多和多对一关系映射 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.准备测试环境(创建数据库表)  1>.创建customers表: ...

  8. Mybatis对象关系映射 one2one,one2many,many2many

    MyBatis中的高级映射一般要借助select元素中的resultMap属性进行实现,通过此属性配置实现一对一,一对多等关系映射的实现 一对一映射:association 一对多映射:collect ...

  9. 【mybatis xml】数据层框架应用--Mybatis(三)关系映射之一对一关系映射

    实际的开发中,对数据库的操作常常会涉及到多张表,这在面向对象中就涉及到了对象与对象之间的关联关系. 针对多表之间的操作,MyBatis提供了关联映射,通过关联映射就可以很好的处理对象与对象之间的关联关 ...

随机推荐

  1. BBS(第一天)项目之 注册功能实现通过forms验证与 前端ajax请求触发查询数据库判断用户是否存在的功能实现

    1.BBS项目之注册功能通过forms验证 from django import forms from blog.models import User from django.contrib.auth ...

  2. 在cxGrid表格中如何获得当前列的字段名

    var GridDBTableView:TcxGridDBTableView; ColIndex:Integer; FieldName:string; begin GridDBTableView := ...

  3. MySQL中的重做日志(redo log),回滚日志(undo log),以及二进制日志(binlog)的简单总结

    MySQL中有六种日志文件,分别是:重做日志(redo log).回滚日志(undo log).二进制日志(binlog).错误日志(errorlog).慢查询日志(slow query log).一 ...

  4. VUE - 相对路径

    background-image背景图片路径问题可以这样解决:1.先在data里面导入这张图片,例如:                bg:require('./openIndexBG2.jpg')2 ...

  5. 1、python环境安装及软件介绍

    软件: python3.0 下载地址:https://www.python.org/downloads/windows/ pycharm 下载地址: https://www.jetbrains.com ...

  6. SAP 图形页面

    话不多说,先上炫图. *&---------------------------------------------------------------------* *& Repor ...

  7. java学习笔记(十):scanner输入

    可以通过 Scanner 类来获取用户的输入. 通过next()类和nextLine()类来获取字符串. 通过 Scanner 类的 next() 类来获取输入的字符串. import java.ut ...

  8. day39 mysql数据库基本操作

    什么是数据库 用来存储数据的仓库 数据库可以在硬盘及内存中存储数据 主要学习硬盘中存储数据,因为内存中的数据总有一天会丢失 数据库与文件存储数据区别 (公司的开发是综合内容的) 数据库本质也是通过文件 ...

  9. NodeJs命令

    cd命令,就是change directory的缩写,表示更改当前目录 cls命令,清屏.清屏幕命令(CLS,CLear Screen) tab键,自动补全. 上键,提示最近的命令   在cmd窗口 ...

  10. MySQL 树节点递归遍历所以子节点

    DELIMITER $$ DROP FUNCTION IF EXISTS `getChildList`$$ CREATE FUNCTION `getChildList`(rootId INT) RET ...