一、一对一关系映射
使用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 String toString() { 44 return "OrderItem{" + 45 "itemid=" + itemid + 46 ", count=" + count + 47 ", subtotal=" + subtotal + 48 ", pid=" + pid + 49 ‘}‘; 50 } 51 }
orderitem实体类
4、类似于上面讲到的使用resultMap的方式,我们在Order中添加上orderitem这一属性,作用就是维护Order和Orderitem的关联关系
1 package cn.mybatis.po; 2 3 import java.util.Date; 4 import java.util.List; 5 6 public class Order { 7 8 private int oid; 9 private double total; 10 private Date ordertime; 11 private String name; 12 private User user; 13 14 private List<OrderItem> orderItems; 15 16 public int getOid() { 17 return oid; 18 } 19 20 public void setOid(int oid) { 21 this.oid = oid; 22 } 23 24 public double getTotal() { 25 return total; 26 } 27 28 public void setTotal(double total) { 29 this.total = total; 30 } 31 32 public Date getOrdertime() { 33 return ordertime; 34 } 35 36 public void setOrdertime(Date ordertime) { 37 this.ordertime = ordertime; 38 } 39 40 public String getName() { 41 return name; 42 } 43 44 public User getUser() { 45 return user; 46 } 47 48 public void setUser(User user) { 49 this.user = user; 50 } 51 52 public void setName(String name) { 53 this.name = name; 54 } 55 56 public List<OrderItem> getOrderItems() { 57 return orderItems; 58 } 59 60 public void setOrderItems(List<OrderItem> orderItems) { 61 this.orderItems = orderItems; 62 } 63 64 @Override 65 public String toString() { 66 return "Order{" + 67 "oid=" + oid + 68 ", total=" + total + 69 ", ordertime=" + ordertime + 70 ", name=‘" + name + ‘\‘‘ + 71 ", user=" + user + 72 ", orderItems=" + orderItems + 73 ‘}‘; 74 } 75 }
修改后的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}]}
原文地址:https://www.cnblogs.com/fsmly/p/10339619.html