Mybatis实现一对一和一对多关系(案例版)

目录

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.实现一对多


 

项目结构图

Mybatis实现一对一和一对多关系(案例版)_第1张图片

环境:

开发工具:Intellij idea 2018.3版本

JDK:1.8

数据库:Mysql 8.0.11

Mybatis:3.4.1

 

 

在讲案例前先明确什么是一对一,一对多。

1.  一对一关系和一对多关系

(以下来自于黑马程序员的视频笔记) 

  • 什么关系属于一对一

     一个身份证对应着一个公民,一个公民也对应着一张身份证

  • 一对一的建表原则:

两种对应方式:

唯一外键对应:在任意一方加一个外键,然后加个unique约束条件。本文中采用这种

主键对应:就是主键对主键

Mybatis实现一对一和一对多关系(案例版)_第2张图片

  • 什么样关系属于一对多?

   一个用户对应多个订单,一个订单只能属于一个用户

   一个客户对应多个联系人,一个联系人只能属于某一个客户。

  • 一对多的建表原则:

       在多的一方创建外键指向一的一方的主键

Mybatis实现一对一和一对多关系(案例版)_第3张图片

 


 这里用到的是两张表,订单表(Orders)和用户表(User)。一个订单对应一个用户,一个用户可以对应着多个订单。虽然这是一对多关系,但是如果从订单角度看,一个订单只能对应一个用户。勉强可以算作一对一,本文中为了缩减代码量,就直接用两个表演示一对一和一对多。下面进入案例。有些代码是重复的,因此得先把这些准备工作做了

2.准备

2.1创建两张表

  创建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);

2.2 创建工程

可以创建java工程也可以创建javaEE项目,反正测试使用Junit。具体如何创建可以参考我另外一篇文章https://blog.csdn.net/Vibugs/article/details/85246420

项目结构图

 Mybatis实现一对一和一对多关系(案例版)_第4张图片

导入jar包:

Mybatis实现一对一和一对多关系(案例版)_第5张图片

 

2.3 创建实体类

创建Order实体类

Mybatis实现一对一和一对多关系(案例版)_第6张图片

根据一对一的实体类原则,在没有外键的一方实体类中包含外键一方的对象 , 因此Order类中要有User的对象

 

创建User类

Mybatis实现一对一和一对多关系(案例版)_第7张图片

 根据一对多的建立实体类的原则,在没有外键的一方(user)的实体类创建另一方的List集合(List),因此 User类中带有order类的list集合。

 

2.4 创建Mybatis-config.xml文件




    
    

    
   
       
      

   

    
    
        
            
            

            
            
                
                
                
                

            
        
    
    
    
    
        
        
    

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

2.5 创建SessionFactory的Util类

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标签输出

实现思路:根据一对一的建表原则,在任意一方(订单表)建立唯一外键指向另一方的主键,确定要查询的唯一订单唯一用户。再根据一对一建立实体类的原则,在没有外键的一方实体类中包含外键一方的对象,显示时通过这个对象获取到关联的用户信息。

Mybatis实现一对一和一对多关系(案例版)_第8张图片

实现过程:sql查询语句中设置两个条件:

    条件1 订单的外键user_id =用户的主键id 

    条件2: 订单的主键id=你要查询的值。

结果用resultMap结果集返回,类型是Order型,order实体类中有user对象,因此关联的用户信息就可以从里面获取到(即order.getUser()) 。实体类时关联了,但是映射的时候还是得指明关联关系,因此需要在resultMap标签中使用association标签指定。

 

3.1 创建订单类的sql映射文件:OrderMapper.xml





   
    
    
    
        
        
        
        
        
        
        
    

    
    
        
        
        
        
        
        
    

 

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查询订单信息。

  • 属性:id的值就是OrderMapper接口类 的方法名,parameterType是输入的参数,这里是int型。resultMap:将结果以结果集的形式显示。
  • SQL语句:这里有两个点需要知道。

       

resultMap标签:

属性

id 当前命名空间中的一个唯一标识,用于标识一个结果映射。
type 类的完全限定名, 或者一个类型别名(就是决定resultMap的类型)
autoMapping 如果设置这个属性,MyBatis将会为本结果映射开启或者关闭自动映射。 这个属性会覆盖全局的属性 autoMappingBehavior。默认值:未设置(unset)

字段

  • constructor - 用于在实例化类时,注入结果到构造方法中
    • idArg - ID 参数;标记出作为 ID 的结果可以帮助提高整体性能
    • arg - 将被注入到构造方法的一个普通结果
  • id – 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能
  • result – 注入到字段或 JavaBean 属性的普通结果
  • association – 一个复杂类型的关联;许多结果将包装成这种类型
    • 嵌套结果映射 – 关联本身可以是一个 resultMap 元素,或者从别处引用一个
  • collection – 一个复杂类型的集合
    • 嵌套结果映射 – 集合本身可以是一个 resultMap 元素,或者从别处引用一个
  • discriminator – 使用结果值来决定使用哪个 resultMap
    • case – 基于某些值的结果映射
      • 嵌套结果映射 – case 本身可以是一个 resultMap 元素,因此可以具有相同的结构和元素,或者从别处引用一个

本例中两个resultMap的type不一样,select标签指定的oneToOneOrderResultMap是Order类型的,而association关联的UserMap是User类型的。那输出时怎么输出呢,是输出order对象还是user对象呢。其实是输出Order对象,我们在Order实体类中不是定义了user对象吗,可以直接通过order.getUser.getXxx()方法输出User信息。

 

association标签:

这个标签上面代码注释里面有对它几个属性的解释。在这里就不多说了

记得将OrderMapper.xml导入到Mybatis-config.xml文件中

 

 3.2 创建接口类:OrderMapper

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);

    
}

 

3.3 测试类:MapperTest

 
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集合,通过这个集合获取唯一用户下的所有订单。

Mybatis实现一对一和一对多关系(案例版)_第9张图片

过程很相似,直接附上步骤

创建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();
    }

 

测试结果:

Mybatis实现一对一和一对多关系(案例版)_第10张图片

 

结束语:希望各位点赞 

你可能感兴趣的:(javaEE)