栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

mybatis中的四种关联关系应该如何理解?

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

mybatis中的四种关联关系应该如何理解?

目录

表之间的关联关系

实体类

映射文件

映射接口

测试类

一对多关联关系

多对一关联关系

一对一关联

实体类

多对多关联

表之间的关联关系

表与表之间一般存在三种关系,即一对一,一对多,多对多关系。 关联关系是有方向的
  1)一对多关联:一个老师可以教多个学生,多个学生只有一个老师来教,站在老师方,就是一对多关联.
  2)多对一关联:一个老师可以教多个学生,多个学生只有一个老师来教,站在学生方,就是多对一关联.
  3)一对一关联:一个老师辅导一个学生,一个学生只请教一个老师.学生和老师是一对一.
  4)多对多关联:园区划线的车位和园区的每一辆车.任意一个车位可以停任意一辆车.任意一车辆车可以停在任意一个车位上。

在实际项目开发中,一对多是非常常见的关系,比如,一个班级可以有多个学生,一个学生只能属于一个班级,班级和学生是一对多的关系,而学生和班级是多对一的关系。数据库中一对多关系通常使用主外键关联,外键列应该在多方,即多方维护关系。下面我们就用一个简单示例来看看MyBatis怎么处理一对多关系。首先,给在数据库创建两个表tb_clazz 和tb_student,并插入测试数据。SQL脚本如下:

drop table if exists tb_clazz;

CREATE TABLE tb_clazz(
id INT PRIMARY KEY AUTO_INCREMENT,
CODE VARCHAr(18),
NAME VARCHAr(18)
);

INSERT INTO tb_clazz(CODE,NAME) VALUES('201803','计算机专业');

drop table if exists tb_student;

CREATE TABLE tb_student(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAr(18),
sex VARCHAr(18),
age INT,
clazz_id INT,
FOREIGN KEY(clazz_id) REFERENCES tb_clazz(id)
);

INSERT INTO tb_student (NAME,sex,age,clazz_id) VALUES('小马','男',23,1) ;
INSERT INTO tb_student (NAME,sex,age,clazz_id) VALUES('小李','女',23,1) ;
INSERT INTO tb_student (NAME,sex,age,clazz_id) VALUES('小明','男',23,1) ;
INSERT INTO tb_student (NAME,sex,age,clazz_id) VALUES('小红','女',23,1) ;

提示:
tb_student表的clazz_id作为外键参照tb_clazz表的主键id。

实体类

在数据库中执行SQL脚本,完成创建数据库和表的操作。接下来,创建一个Clazz对象和一个Student对象分别映射tb_clazz和tb_student表。

班级和学生是一对多的关系,即一个班级可以有多个学生。在Clazz类当中定义了一个students属性,该属性是一个List集合,用来映射一对多的关联关系,表示一个班级有多个学生。

import java.io.Serializable;
import java.util.List;

public class Clazz implements Serializable
{
    private static final long serialVersionUID = 1L;
    private Integer id; // 班级id,主键
    private String code; // 班级编号
    private String name; // 班级名称

    // 班级和学生是一对多的关系,即一个班级可以有多个学生
    private List students;

    public Clazz()
    {
        super();
    }

    public Integer getId()
    {
        return id;
    }

    public void setId(Integer id)
    {
        this.id = id;
    }

    public String getCode()
    {
        return code;
    }

    public void setCode(String code)
    {
        this.code = code;
    }

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public List getStudents()
    {
        return students;
    }

    public void setStudents(List students)
    {
        this.students = students;
    }

    @Override
    public String toString()
    {
        return "Clazz [id=" + id + ", code=" + code + ", name=" + name + "]";
    }

}

班级和学生是一对多的关系,即一个班级可以有多个学生。在Clazz类当中定义了一个students属性,该属性是一个List集合,用来映射一对多的关联关系,表示一个班级有多个学生。

import java.io.Serializable;

public class Student implements Serializable
{
    private static final long serialVersionUID = 1L;
    private Integer id; // 学生id,主键
    private String name; // 姓名
    private String sex; // 性别
    private Integer age; // 年龄

    // 学生和班级是多对一的关系,即一个学生只属于一个班级
    private Clazz clazz;

    public Student()
    {
        super();
    }

    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 String getSex()
    {
        return sex;
    }

    public void setSex(String sex)
    {
        this.sex = sex;
    }

    public Integer getAge()
    {
        return age;
    }

    public void setAge(Integer age)
    {
        this.age = age;
    }

    public Clazz getClazz()
    {
        return clazz;
    }

    public void setClazz(Clazz clazz)
    {
        this.clazz = clazz;
    }

    @Override
    public String toString()
    {
        return "Student [id=" + id + ", name=" + name + ", sex=" + sex + ", age=" + age + "]";
    }

学生和班级是多对一的关系,即一个学生只属于一个班级。在Student类当中定义了一个clazz属性,该属性是一个Clazz类型,用来映射多对一的关联关系,表示该学生所属的班级。

映射文件


    
    
        SELECT * FROM tb_clazz c,tb_student s
        WHERe c.id = s.clazz_id
        AND s.id = #{id}
    

    
     其会根据学生id查询学生信息,由于Student类除了简单的属性id、name、sex和age之外,还有一个关联对象clazz,所以它返回的是一个名为clazzResultMap的resultMap。clazzResutMap中使用了元素映射多对一的关联关系,因为其会根据班级id查询所有学生信息,该查询用于ClazzMapper.xml 中的关联查询。

映射接口
import cn.mybatis.mydemo2.domain.Clazz;

public interface ClazzMapper
{
// 根据id查询班级信息
Clazz selectClazzById(Integer id);
}

import cn.mybatis.mydemo2.domain.Student;

public interface StudentMapper
{
// 根据id查询学生信息
Student selectStudentById(Integer id);
}

测试类
public class App
{
public static void main(String[] args) throws Exception
{
// 读取mybatis-config.xml文件
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
// 初始化mybatis,创建SqlSessionFactory类的实例
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 创建Session实例
SqlSession session = sqlSessionFactory.openSession();

App app = new App();

app.testSelectClazzById(session);
// t.testSelectStudentById(session);

// 提交事务
session.commit();
// 关闭Session
session.close();
}

// 测试一对多,查询班级Clazz(一)的时候级联查询学生Student(多)
public void testSelectClazzById(SqlSession session)
{
// 获得ClazzMapper接口的代理对象
ClazzMapper cm = session.getMapper(ClazzMapper.class);
// 调用selectClazzById方法
Clazz clazz = cm.selectClazzById(1);
// 查看查询到的clazz对象信息
System.out.println(clazz.getId() + " " + clazz.getCode() + " " + clazz.getName());
// 查看clazz对象关联的学生信息
List students = clazz.getStudents();
for (Student stu : students)
{
System.out.println(stu);
}
}

// 测试多对一,查询学生Student(多)的时候级联查询 班级Clazz(一)
public void testSelectStudentById(SqlSession session)
{
// 获得StudentMapper接口的代理对象
StudentMapper sm = session.getMapper(StudentMapper.class);
// 调用selectStudentById方法
Student stu = sm.selectStudentById(1);
// 查看查询到的Student对象信息
System.out.println(stu);
// 查看Student对象关联的班级信息
System.out.println(stu.getClazz());
}
}

一对多关联关系


  客户和订单就是典型的一对多关联关系。
  一个客户名下可以有多个订单。
  客户表是一方,订单表是多方.客户一中持有订单的集合。
  使用一对多的关联关系,可以满足查询客户的同时查询该客户名下的所有订单。

 
   
    
        
        
        
        
        

        
        
            
            
            
            
            
        
    
    
        select o.id oid,orderNumber,orderPrice,customer_id,c.id cid,name,age
        from orders o inner join customer c on o.customer_id = c.id
        where o.id=#{id}
    
  

一对一关联

在实际项目开发中,经常存在一对一关系,比如一个人只能有一个身份证,一个身份证只能给一个人使用,这就是一对一的关系。一对一关系推荐使用唯一主外键关联,即两张表使用外键关联,由于是一对一关联,因此还需要给外键列增加unique唯一约束。

drop table if exists tb_card;

create table tb_card (
id int primary key auto_increment,
code varchar(18)
);

insert into tb_card(code) values ('432801198009191038');

drop table if exists tb_person;

create table tb_person (
id int primary key auto_increment,
name varchar(18),
sex varchar(18),
age int,
card_id int unique,
foreign key(card_id) peferences tb_card(id)
);

insert into tb_person(name, sex, age, card_id) values ('jack','男',23,1) ;

提示:
tb_person表的card_id作为外键,其参照tb_card表的主键id,因为是一对一关系,即一个card只能让一个person使用,所以card_id做成了唯一键约束。如此一来,当一个person使用了一个card之后,其他的person就不能使用该card了。

实体类

接下来,创建一个Card对象和一个Person对象分别映射tb_card和tb_person表。

package cn.mybatis.mydemo.domain;

import java.io.Serializable;

public class Card implements Serializable
{
private static final long serialVersionUID = 1L;
private Integer id; // 主键id
private String code; // 身份证编号

public Card()
{
super();
}

public Integer getId()
{
return id;
}

public void setId(Integer id)
{
this.id = id;
}

public String getCode()
{
return code;
}

public void setCode(String code)
{
this.code = code;
}

@Override
public String toString()
{
return "Card [id=" + id + ", code=" + code + "]";
}

}


package cn.mybatis.mydemo.domain;

import java.io.Serializable;

public class Person implements Serializable
{
private static final long serialVersionUID = 1L;
private Integer id; // 主键id
private String name; // 姓名
private String sex; // 性别
private Integer age; // 年龄

// 人和身份证是一对一的关系,即一个人只有一个身份证
private Card card;

public Person()
{
super();
}

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 String getSex()
{
return sex;
}

public void setSex(String sex)
{
this.sex = sex;
}

public Integer getAge()
{
return age;
}

public void setAge(Integer age)
{
this.age = age;
}

public Card getCard()
{
return card;
}

public void setCard(Card card)
{
this.card = card;
}

@Override
public String toString()
{
return "Person [id=" + id + ", name=" + name + ", sex=" + sex + ", age=" + age + "]";
}

}


  
  
        select * from tb_person where id = #{id}
    

    
    
        
        
        
        
        
        
        
    

public class App
{
    public static void main(String[] args) throws Exception
    {
        // 读取mybatis-config.xml文件
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");

        // 初始化mybatis,创建SqlSessionFactory类的实例
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        // 创建Session实例
        SqlSession session = sqlSessionFactory.openSession();

        Person p = session.selectOne("cn.mybatis.mydemo.mapper.PersonMapper.selectPersonById", 1);
        System.out.println(p);
        System.out.println(p.getCard().getCode());

        // 获得mapper接口的代理对象
        PersonMapper pm = session.getMapper(PersonMapper.class);
        // 直接调用接口的方法,查询id为1的Peson数据
        Person p2 = pm.selectPersonById(1);
        // 打印Peson对象
        System.out.println(p2);
        // 打印Person对象关联的Card对象
        System.out.println(p2.getCard());

        // 提交事务
        session.commit();
        // 关闭Session
        session.close();
    }
}

多对多关联

重点是中间表,中间表对关系进行描述。意味着实体类中可能包含对方的集合。
 

总结:无论是什么关联关系,如果某方持有另一方的集合,则使用标签完成映射,如果某方持有另一方的对象,则使用标签完成映射。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1020300.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号