Mybatis关系映射

Posted 风沙迷了眼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis关系映射相关的知识,希望对你有一定的参考价值。

一、一对一关系映射

使用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的实体类

 1 package cn.mybatis.po;
 2 
 3 public class User {
 4     private int uid;
 5     private String username;
 6     private String password;
 7     private String address;
 8     private String sex;
 9 
10     public int getUid() {
11         return uid;
12     }
13 
14     public void setUid(int uid) {
15         this.uid = uid;
16     }
17 
18     public String getUsername() {
19         return username;
20     }
21 
22     public String getPassword() {
23         return password;
24     }
25 
26     public String getAddress() {
27         return address;
28     }
29 
30     public String getSex() {
31         return sex;
32     }
33 
34     public void setUsername(String username) {
35         this.username = username;
36     }
37 
38     public void setPassword(String password) {
39         this.password = password;
40     }
41 
42     public void setAddress(String address) {
43         this.address = address;
44     }
45 
46     public void setSex(String sex) {
47         this.sex = sex;
48     }
49 
50     public User(String username, String password, String address, String sex) {
51         this.username = username;
52         this.password = password;
53         this.address = address;
54         this.sex = sex;
55     }
56 
57     public User() {
58     }
59 
60     @Override
61     public String toString() {
62         return "User{" +
63                 "uid=" + uid +
64                 ", username=\'" + username + \'\\\'\' +
65                 ", password=\'" + password + \'\\\'\' +
66                 ", address=\'" + address + \'\\\'\' +
67                 ", sex=\'" + sex + \'\\\'\' +
68                 \'}\';
69     }
70 }
User类
 1 package cn.mybatis.po;
 2 
 3 import java.util.Date;
 4 
 5 public class Order {
 6 
 7     private int oid;
 8     private double total;
 9     private Date ordettime;
10     private String name;
11 
12     public int getOid() {
13         return oid;
14     }
15 
16     public void setOid(int oid) {
17         this.oid = oid;
18     }
19 
20     public double getTotal() {
21         return total;
22     }
23 
24     public void setTotal(double total) {
25         this.total = total;
26     }
27 
28     public Date getOrdettime() {
29         return ordettime;
30     }
31 
32     public void setOrdettime(Date ordettime) {
33         this.ordettime = ordettime;
34     }
35 
36     public String getName() {
37         return name;
38     }
39 
40     public void setName(String name) {
41         this.name = name;
42     }
43 
44     @Override
45     public String toString() {
46         return "Order{" +
47                 "oid=" + oid +
48                 ", total=" + total +
49                 ", ordettime=" + ordettime +
50                 ", name=\'" + name + \'\\\'\' +
51                 \'}\';
52     }
53 }
Order类

 

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

 1 package cn.mybatis.po;
 2 
 3 public class OrderPoJo extends Order{
 4 
 5     private String username;
 6     private String address;
 7     private String sex;
 8 
 9     public String getUsername() {
10         return username;
11     }
12 
13     public void setUsername(String username) {
14         this.username = username;
15     }
16 
17     public String getAddress() {
18         return address;
19     }
20 
21     public void setAddress(String address) {
22         this.address = address;
23     }
24 
25     public String getSex() {
26         return sex;
27     }
28 
29     public void setSex(String sex) {
30         this.sex = sex;
31     }
32 
33     @Override
34     public String toString() {
35         return "OrderPoJo{" +
36                 super.toString() +
37                 "username=\'" + username + \'\\\'\' +
38                 ", address=\'" + address + \'\\\'\' +
39                 ", sex=\'" + sex + \'\\\'\' +
40                 \'}\';
41     }
42 }

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

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

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <!DOCTYPE mapper
 3         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 4         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 5 <!--mapper为根元素,namespace指定了命名空间-->
 6 <mapper namespace="cn.mybatis.mapper.OrderMapper">
 7 
 8     <select id="findOrderAndUser" parameterType="int" resultType="orderPoJo">
 9         SELECT orders.*,
10                 user.username,user.sex,user.address
11                 FROM orders,USER
12                 WHERE oid = #{id} AND user.uid = orders.uid
13     </select>
14 
15 </mapper>

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

  

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

 1 package cn.mybatis.mapper;
 2 
 3 
 4 import cn.mybatis.po.OrderPoJo;
 5 import org.apache.ibatis.io.Resources;
 6 import org.apache.ibatis.session.SqlSession;
 7 import org.apache.ibatis.session.SqlSessionFactory;
 8 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
 9 import org.junit.Before;
10 import org.junit.Test;
11 
12 import java.io.InputStream;
13 
14 public class OrderMapperTest {
15 
16     private SqlSessionFactory sqlSessionFactory;
17 
18     @Before
19     public void setUp() throws Exception {
20         InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
21         sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
22     }
23 
24     @Test
25     public void testFindOrderAndUser() throws Exception {
26         SqlSession sqlSession = sqlSessionFactory.openSession();
27         OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
28 
29         OrderPoJo orderPoJo = orderMapper.findOrderAndUser(3);
30 
31         System.out.println(orderPoJo);
32 
33         sqlSession.close();
34 
35     }
36 
37 }

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

使用resultMap在配置文件中实现

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

 1 package cn.mybatis.po;
 2 
 3 import java.util.Date;
 4 
 5 public class Order {
 6 
 7     private int oid;
 8     private double total;
 9     private Date ordertime;
10     private String name;
11     private User user;
12 
13     public int getOid() {
14         return oid;
15     }
16 
17     public void setOid(int oid) {
18         this.oid = oid;
19     }
20 
21     public double getTotal() {
22         return total;
23     }
24 
25     public void setTotal(double total) {
26         this.total = total;
27     }
28 
29     public Date getOrdertime() {
30         return ordertime;
31     }
32 
33     public void setOrdertime(Date ordertime) {
34         this.ordertime = ordertime;
35     }
36 
37     public String getName() {
38         return name;
39     }
40 
41     public User getUser() {
42         return user;
43     }
44 
45     public void setUser(User user) {
46         this.user = user;
47     }
48 
49     public void setName(String name) {
50         this.name = name;
51     }
52 
53     @Override
54     public String toString() {
55         return "Order{" +
56                 "oid=" + oid +
57                 ", total=" + total +
58                 ", ordertime=" + ordertime +
59                 ", name=\'" + name + \'\\\'\' +
60                 ", user=" + user +
61                 \'}\';
62     }
63 }

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

 1     <!--
 2         订单关联User的查询resultMap
 3         将查询的结果全部映射到Order类中
 4     -->
 5     <resultMap id="OrderResultMap" type="cn.mybatis.po.Order">
 6         <!--配置映射订单-->
 7         <id column="oid" property="oid"></id>
 8         <result column="total" property="total"></result>
 9         <result column="ordertime" property="ordertime"></result>
10         <result column="name" property="name"></result>
11 
12         <!--配置关联用户信息-->
13         <!--
14             association:用于映射关联查询单个对象的信息
15             property:用于设置将关联信息映射到Order的哪个属性中
16             -->
17         <association property="user" javaType="cn.mybatis.po.User">
18             <id column="uid" property="uid"></id>
19             <result column="username" property="username"></result>
20             <result column="address" property="address"></result>
21             <result column="sex" property="sex"></result>
22         </association>
23     </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

 1 package cn.mybatis.po;
 2 
 3 public class OrderItem {
 4 
 5     private int itemid;
 6     private int count;
 7     private double subtotal;
 8     private int pid;
 9 
10     public int getItemid() {
11         return itemid;
12     }
13 
14     public void setItemid(int itemid) {
15         this.itemid = itemid;
16     }
17 
18     public int getCount() {
19         return count;
20     }
21 
22     public void setCount(int count) {
23         this.count = count;
24     }
25 
26     public double getSubtotal() {
27         return subtotal;
28     }
29 
30     public void setSubtotal(double subtotal) {
31         this.subtotal = subtotal;
32     }
33 
34     public int getPid() {
35         return pid;
36     }
37 
38     public void setPid(int pid) {
39         this.pid = pid;
40     }
41 
42     @Override
43     public以上是关于Mybatis关系映射的主要内容,如果未能解决你的问题,请参考以下文章

mybatis 关系映射

mybatis xml数据层框架应用--Mybatis关系映射之一对多关系映射

mybatis xml数据层框架应用--Mybatis关系映射之一对一关系映射

MyBatis框架

Java 中mybatis 关系映射,比如:一对多

Mybatis之关联关系(一对多多对多)