目录
1. 一对一关系和一对多关系
2.准备
2.1创建两张表
2.2 创建工程
2.3 创建实体类
2.4 创建Mybatis-config.xml文件
2.5 创建SessionFactory的Util类
3. 实现一对一
3.1 创建订单类的sql映射文件:OrderMapper.xml
3.2 创建接口类:OrderMapper
3.3 测试类:MapperTest
4.实现一对多
项目结构图
环境:
开发工具:Intellij idea 2018.3版本
JDK:1.8
数据库:Mysql 8.0.11
Mybatis:3.4.1
在讲案例前先明确什么是一对一,一对多。
1. 一对一关系和一对多关系
(以下来自于黑马程序员的视频笔记)
一个身份证对应着一个公民,一个公民也对应着一张身份证
两种对应方式:
唯一外键对应:在任意一方加一个外键,然后加个unique约束条件。本文中采用这种
主键对应:就是主键对主键
一个用户对应多个订单,一个订单只能属于一个用户
一个客户对应多个联系人,一个联系人只能属于某一个客户。
在多的一方创建外键指向一的一方的主键
这里用到的是两张表,订单表(Orders)和用户表(User)。一个订单对应一个用户,一个用户可以对应着多个订单。虽然这是一对多关系,但是如果从订单角度看,一个订单只能对应一个用户。勉强可以算作一对一,本文中为了缩减代码量,就直接用两个表演示一对一和一对多。下面进入案例。有些代码是重复的,因此得先把这些准备工作做了
2.准备
创建User表,插入三条数据
CREATE TABLE `user` (
`uid` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`birthday` date DEFAULT NULL COMMENT '生日',
`sex` char(1) DEFAULT NULL COMMENT '性别',
`address` varchar(256) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=UTF8MB4;
INSERT INTO `user` VALUES ('1', '王五', null, '2', null);
INSERT INTO `user` VALUES ('10', '张三', '2014-07-10', '1', '北京市');
INSERT INTO `user` VALUES ('16', '张小明', null, '1', '河南郑州');
创建Orders表,插入两条数据
CREATE TABLE `orders` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL COMMENT '下单用户id',
`number` varchar(32) NOT NULL COMMENT '订单号',
`createtime` datetime NOT NULL COMMENT '创建订单时间',
`note` varchar(100) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`),
KEY `FK_orders_1` (`user_id`),
CONSTRAINT `FK_orders_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=UTF8MB4;
INSERT INTO `orders` VALUES ('3', '1', '1000010', '2015-02-04 13:22:35', null);
INSERT INTO `orders` VALUES ('4', '1', '1000011', '2015-02-03 13:22:41', null);
可以创建java工程也可以创建javaEE项目,反正测试使用Junit。具体如何创建可以参考我另外一篇文章https://blog.csdn.net/Vibugs/article/details/85246420
项目结构图
导入jar包:
创建Order实体类
根据一对一的实体类原则,在没有外键的一方实体类中包含外键一方的对象 , 因此Order类中要有User的对象
创建User类
根据一对多的建立实体类的原则,在没有外键的一方(user)的实体类创建另一方的List集合(List
MySql.properties配置文件
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/demo?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8&useSSL=false
jdbc.username=root
jdbc.password=12315
package cn.svllen.mybatis.util;
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 java.io.InputStream;
/**
* @program: MybatisDay01
* @description: 创建SessionFactory的util类
* @author: svllen
* @create: 2019-03-23 10:52
**/
public class SessionFactoryUtil {
public static SqlSessionFactory sqlSessionFactory;
static{
try{
InputStream inputStream = Resources.getResourceAsStream("Mybatis-config.xml");
//构建工厂
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}catch (Exception e){
e.printStackTrace();
}
}
public static SqlSession getCurrentSession(){
return sqlSessionFactory.openSession();
}
}
3. 实现一对一
需求:使用一对一的查找方式,输入订单id查询订单信息,嵌套用户顺便查询出订单所属的用户信息。在sql映射文件中用resultMap标签输出
实现思路:根据一对一的建表原则,在任意一方(订单表)建立唯一外键指向另一方的主键,确定要查询的唯一订单和唯一用户。再根据一对一建立实体类的原则,在没有外键的一方实体类中包含外键一方的对象,显示时通过这个对象获取到关联的用户信息。
实现过程:sql查询语句中设置两个条件:
条件1 订单的外键user_id =用户的主键id
条件2: 订单的主键id=你要查询的值。
结果用resultMap结果集返回,类型是Order型,order实体类中有user对象,因此关联的用户信息就可以从里面获取到(即order.getUser()) 。实体类时关联了,但是映射的时候还是得指明关联关系,因此需要在resultMap标签中使用association标签指定。
select标签:
1.我给两个表的主键id都起了别名,因为两个表的主键都是一样的名称,当你把结果映射到resultMap的时候会出现显示错误的bug。具体可查看我另一篇文章 https://blog.csdn.net/Vibugs/article/details/86540185
2.我们的查询条件有两个,一个是通过order_id查询用户信息,第二是通过外键查询用户信息。因此在sql语句中查询条件是 o.user_id = u.id(即订单表中的user_id外键 = 用户表中的id主键)。但是要插入匹配符#{}的应该是订单的id主键,毕竟我们是通过订单id查询订单信息。
resultMap标签:
属性
id | 当前命名空间中的一个唯一标识,用于标识一个结果映射。 |
type | 类的完全限定名, 或者一个类型别名(就是决定resultMap的类型) |
autoMapping | 如果设置这个属性,MyBatis将会为本结果映射开启或者关闭自动映射。 这个属性会覆盖全局的属性 autoMappingBehavior。默认值:未设置(unset) |
字段
本例中两个resultMap的type不一样,select标签指定的oneToOneOrderResultMap是Order类型的,而association关联的UserMap是User类型的。那输出时怎么输出呢,是输出order对象还是user对象呢。其实是输出Order对象,我们在Order实体类中不是定义了user对象吗,可以直接通过order.getUser.getXxx()方法输出User信息。
association标签:
这个标签上面代码注释里面有对它几个属性的解释。在这里就不多说了
记得将OrderMapper.xml导入到Mybatis-config.xml文件中
package cn.svllen.mybatis.domain;
/**
* @program: MybatisDay01
* @description: orderMapper的接口类,用来跟OrderMapper.xml关联起来。里面的一个select标签(也可以回其他标签,insert,update)对应这里的一个方法
* @author: svllen
* @create: 2019-03-26 15:30
**/
public interface OrderMapper {
//使用一对一的查找方式,输入订单id查询订单信息,嵌套用户顺便查询出订单所属的用户信息
Order OneToOneByOrder(int orderId);
}
public class MapperTest {
/**
* @Description: 一对一的测试,输入订单id查询订单信息,嵌套用户顺便查询出订单所属的用户信息
* @Param:
* @return:
* @Author: svllen
* @Date: 2019/3/27
*/
@Test
public void OneToOneByOrderTest(){
SqlSession sqlSession = SessionFactoryUtil.getCurrentSession();
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
int orderId = 4;
//查询结果
Order order = orderMapper.OneToOneByOrder(orderId);
//显示结果
System.out.println("查询到的订单为:" + order);
System.out.println("该订单用户为:" + order.getUser());
sqlSession.commit();
sqlSession.close();
}
}
结果:
4.实现一对多
需求:通过输入用户id查询多个订单信息,用户信息也要返回
实现思路:根据一对多建表原则(在order创建外键指向user的主键),通过order的外键确定要查找的唯一用户和至少一个的订单的关系,再根据一对多建实体类的原则,在user实体类中有order的List
过程很相似,直接附上步骤
创建userMapper接口类:
package cn.svllen.mybatis.domain;
import java.util.List;
/**
* @program: MybatisDay01
* @description: usermapper的接口类,实现Mapper动态代理开发。取代传统的Dao,DaoImpl这种开发模式。与userMapper形成关联
* @author: svllen
* @create: 2019-03-25 10:03
**/
public interface UserMapper {
/*为了跟mapper.xml文件产生关联,这里有四个原则
* 1. 接口方法名等于id名
* 2. 返回值类型与resultType的一样
* 3. 方法的形参跟parameterType一样
* 4. 在.xml文件中,命名空间的值是接口类的全路径
*/
//测试一对多的关系,通过输入用户id查询多个订单信息,用户信息也要返回
User oneToManyByUser(int userId);
}
创建userMapper.xml
创建测试方法:
/**
* @Description: 一对多的测试, 通过输入用户id查询多个订单信息,用户信息也要返回
* @Param:
* @return:
* @Author: svllen
* @Date: 2019/3/29
*/
@Test
public void oneToManyByUserTest(){
SqlSession sqlSession = SessionFactoryUtil.getCurrentSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//设置查询条件
int userId = 16;
User user = userMapper.oneToManyByUser(userId);
System.out.println("你查到的用户信息为:" + user +"\n该用户下的订单有:");
List orderList = user.getOrderList();
for (Order order : orderList){
System.out.println(order);
}
sqlSession.commit();
sqlSession.close();
}
测试结果:
结束语:希望各位点赞