Mybatis---多表联合查询(1)
- 前言
- 测试准备
- 一、一对一
- 新建方法
- 添加关联
- 测试
- 二、一对多
- 新建实体类
- 添加方法
- 添加关联
- 测试
前言
在开发过程中单表查询不能满足项目需求分析功能,对于复杂业务来讲,关联的表有几张,甚至几十张并且表与表之间的关系相当复杂。为了能够实业复杂功能业务,就必须进行多表查询,在mybatis中提供了多表查询的结果时映射标签,可以实现表之间的一对一、一对多、多对多关系映射
测试准备
案例所需数据库脚本
SET FOREIGN_KEY_CHECKS=0;-- ----------------------------
-- Table structure for car
-- ----------------------------
DROP TABLE IF EXISTS `car`;
CREATE TABLE `car` (`cid` int(11) NOT NULL AUTO_INCREMENT,`cname` varchar(20) DEFAULT NULL,`pid` int(11) NOT NULL,PRIMARY KEY (`cid`) USING BTREE,KEY `cp` (`pid`) USING BTREE,CONSTRAINT `car_ibfk_1` FOREIGN KEY (`pid`) REFERENCES `person` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;-- ----------------------------
-- Records of car
-- ----------------------------
INSERT INTO `car` VALUES ('1', '忆柳的购物车', '2');
INSERT INTO `car` VALUES ('2', '梦琪的购物车', '1');
INSERT INTO `car` VALUES ('3', '新柔的购物车', '5');
INSERT INTO `car` VALUES ('4', '慕青的购物车', '3');
INSERT INTO `car` VALUES ('5', '初夏的购物车', '4');-- ----------------------------
-- Table structure for order
-- ----------------------------
DROP TABLE IF EXISTS `order`;
CREATE TABLE `order` (`oid` int(11) NOT NULL AUTO_INCREMENT,`oname` varchar(255) DEFAULT NULL,`pid` int(11) DEFAULT NULL,PRIMARY KEY (`oid`) USING BTREE,KEY `op` (`pid`) USING BTREE,CONSTRAINT `order_ibfk_1` FOREIGN KEY (`pid`) REFERENCES `person` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;-- ----------------------------
-- Records of order
-- ----------------------------
INSERT INTO `order` VALUES ('1', '荣耀MagicBook 2019 14英寸轻薄窄边框', '2');
INSERT INTO `order` VALUES ('2', '小米 (MI)Ruby 2019款 15.6英寸金属轻薄', '1');
INSERT INTO `order` VALUES ('3', '戴尔灵越14 燃 14英寸英特尔酷睿i5轻薄窄边框', '3');
INSERT INTO `order` VALUES ('4', '联想(Lenovo)小新14英寸 锐龙版R5', '4');
INSERT INTO `order` VALUES ('5', '红辣椒7X 4+64GB 学生智能手机', '5');
INSERT INTO `order` VALUES ('6', '荣耀10青春版 幻彩渐变', '1');
INSERT INTO `order` VALUES ('7', 'OPPO K1 全面屏手机', '2');
INSERT INTO `order` VALUES ('8', '卡梵蒂GAVADI 鳄鱼皮钱包', '5');
INSERT INTO `order` VALUES ('9', '七匹狼钱包', '2');
INSERT INTO `order` VALUES ('10', '金利来(Goldlion)男士钱包', '1');-- ----------------------------
-- Table structure for person
-- ----------------------------
DROP TABLE IF EXISTS `person`;
CREATE TABLE `person` (`id` int(11) NOT NULL,`name` varchar(32) DEFAULT NULL,`birthday` date DEFAULT NULL,`address` varchar(32) DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;-- ----------------------------
-- Records of person
-- ----------------------------
INSERT INTO `person` VALUES ('1', 'ddd', '2019-05-08', '北京市');
INSERT INTO `person` VALUES ('2', '忆柳', '2019-05-14', '天津市');
INSERT INTO `person` VALUES ('3', '慕青', '2018-10-17', '上海市');
INSERT INTO `person` VALUES ('4', '初夏', '2017-04-13', '重庆市');
INSERT INTO `person` VALUES ('5', '新柔', '2018-12-29', '广州市');
实体类:Person、Car
package com.entity;import java.util.Date;
import java.util.List;public class Person {private Integer id;private String name;private Date birthday;private String address;private Car car;//一个用户拥有一个carprivate List<Order> orderList;//一个用户拥有多个订单public Person() {}public Person(Integer id, String name, Date birthday, String address, Car car, List<Order> orderList) {this.id = id;this.name = name;this.birthday = birthday;this.address = address;this.car = car;this.orderList = orderList;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public Car getCar() {return car;}public void setCar(Car car) {this.car = car;}public List<Order> getOrderList() {return orderList;}public void setOrderList(List<Order> orderList) {this.orderList = orderList;}@Overridepublic String toString() {return "Person{" +"id=" + id +", name='" + name + '\'' +", birthday=" + birthday +", address='" + address + '\'' +", car=" + car +", orderList=" + orderList +'}';}
}
package com.entity;public class Car {private Integer cid;private String cname;private Integer pid;public Car() {}public Car(Integer cid, String cname, Integer pid) {this.cid = cid;this.cname = cname;this.pid = pid;}public Integer getCid() {return cid;}public void setCid(Integer cid) {this.cid = cid;}public String getCname() {return cname;}public void setCname(String cname) {this.cname = cname;}public Integer getPid() {return pid;}public void setPid(Integer pid) {this.pid = pid;}@Overridepublic String toString() {return "Car{" +"cid=" + cid +", cname='" + cname + '\'' +", pid=" + pid +'}';}
}
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!-- 别名 --><typeAliases><package name="com.entity"/></typeAliases><!-- environments 多环境配置environment 配置数据源transactionManager 事务管理器dataSource 数据源--><environments default="p1"><environment id="p1"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mybatis"/><property name="username" value="root"/><property name="password" value="123456"/></dataSource></environment></environments><!-- 注册映射 --><mappers><mapper resource="PersonMapper.xml"/><mapper resource="CarMapper.xml" /></mappers>
</configuration>
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.ujiuye</groupId><artifactId>mybatics</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><!-- 数据库驱动 版本不能乱用5.1.47 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.6</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13</version><scope>test</scope></dependency><!-- lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.10</version></dependency><!-- 日志文件 --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.12</version></dependency></dependencies>
</project>
目录结构
一、一对一
什么是一对一?举个栗子:一个用户只能拥有一个购物车
新建方法
分别在PersonMapper接口、CarMapper接口中添加方法
public interface PersonMapper {//显示指定person信息public Person findPersonByName(String name);
}
public interface CarMapper {//根据person id查询购物车信息public Car findCarById(int id);
}
添加关联
在Person实体类中添加Car对象(上面的准备中,其实已经添加)
在PersonMapper.xml文件中添加关联(resultMap)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.mapper.PersonMapper"><!-- id:resultMap的名字 type:方法返回值类型 autoMapper:自动映射 --><resultMap id="resultMap1" type="com.entity.Person" autoMapping="true"><!-- id标签表示person表的主键 property表示Person类的属性 column表示person表的字段--><id property="id" column="id"></id><!--association:方法返回值是一个对象时使用该标签 property表示Person类的属性javaType表示CarMapper中方法执行后返回值类型 column表示person表的字段当mybatis 执行完 person表的查询操作后,就会自动执行 CarMapper接口中的 findCarById的方法把查询得到的信息封装到person类下的car对象--><association property="car" javaType="car" column="id"select="com.mapper.CarMapper.findCarById"></association></resultMap><!--id:接口中对应的方法名 --><select id="findPersonByName" resultMap="resultMap1">select * from person where name = #{name}</select>
</mapper>
测试
只调用PerMapper中的方法情况下是否能够获取car表中数据
@Testpublic void test1() throws IOException {//读取配置文件InputStream is = Resources.getResourceAsStream("mybatis-config.xml");//根据配置文件构建工厂SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);//获取会话SqlSession sqlSession = sessionFactory.openSession();//获取Mapper对象PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class);//执行方法Person person = personMapper.findPersonByName("初夏");System.out.println(person);sqlSession.close();}
car表
运行结果(我这里使用了log4j日志打印,可能控制台有所不同)
思路总结:通过name来获得person表中对应的id→person表中的id对应car表中的pid(联表的关键)→通过pid来获得car表中的cname,一对一返回一个对象
二、一对多
什么是一对多?举个栗子:一个用户拥有多个订单
新建实体类
新建一个Order类记录订单
package com.entity;public class Order {private Integer oid;private String oname;private Integer pid;public Order() {}public Order(Integer oid, String oname, Integer pid) {this.oid = oid;this.oname = oname;this.pid = pid;}public Integer getOid() {return oid;}public void setOid(Integer oid) {this.oid = oid;}public String getOname() {return oname;}public void setOname(String oname) {this.oname = oname;}public Integer getPid() {return pid;}public void setPid(Integer pid) {this.pid = pid;}@Overridepublic String toString() {return "Order{" +"oid=" + oid +", oname='" + oname + '\'' +", pid=" + pid +'}';}
}
添加方法
分别在PersonMapper和OrderMapper中添加方法
public Person findPersonByName2(String name);
public interface OrderMapper {//根据person 的 id 查询对应的订单信息public List<Order> findOrderById(int id);}
添加关联
OrderMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.mapper.OrderMapper"><select id="findOrderById" resultType="com.entity.Order">select * from `order` where pid = #{pid}</select>
</mapper>
PersonMapper.xml中添加
<resultMap id="resultMap2" type="person" autoMapping="true"><id column="id" property="id"></id><collection property="orderList" ofType="Order" column="id"select="com.mapper.OrderMapper.findOrderById" ></collection>
</resultMap>
<select id="findPersonByName2" resultMap="resultMap2">select * from person where name = #{name}
</select>
记得在mybatis-config.xml注册映射
<mapper resource="OrderMapper.xml" />
测试
@Testpublic void test3() throws IOException {InputStream is = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);SqlSession sqlSession = sessionFactory.openSession();PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class);Person person = personMapper.findPersonByName2("初夏");List<Order> orderList = person.getOrderList();System.out.println(person);for (Order order : orderList) {System.out.println(order);}sqlSession.close();}
运行结果
思路总结:通过name来获得person表中对应的id→person表中的id对应order表中的pid(联表的关键)→通过pid来获得car表中的oname,与一对一不同的是一对多返回的是一个对象集合