客观世界中的对象很少有孤立存在的,例如班级,往往与班级的学生存在关联关系,如果 得到某个班级的实例,那么应该可以直接获取班级对应的全部学生。反过来,如果已经得到一 个学生的实例,那么也应该可以访问该学生对应的班级。这种实例之间的互相访问就是关联关系。
关联关系是面向对象分析、面向对象设计最重要的知识,MyBatis完全可以理解这种关联 关系,如果映射得当,MyBatis的关联映射将可以大大简化持久层数据的访问。关联关系大致有如下分类。
- 一对一
- 一对多
- 多对多
一对一
在实际项目开发中,经常存在一对一关系,比如一个人只能有一个身份证,一个身份证只 能给一个人使用,这就是一对一的关系。一对一关系推荐使用唯一主外键关联,即两张表使用 外键关联关系,由于是一对一关联,因此还需要给外键列增加unique唯一约束。下面我们就用一个简单示例来看看MyBatis怎么处理一对一关系。
首先,给之前创建的mybatis数据库创建两个表tb_card和tb_person,并插入测试数据。 SQL脚本如下:
`
CREATE TABLE tb_card(
id INT PRIMARY KEY AUTO_INCREMENT,
CODE VARCHAR(18)
);
INSERT INTO tb_card(CODE) VALUES('432801198009191038');
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) REFERENCES 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使用,所以cardjd做成了唯一键约束。如此一来,| 当一个person使用了一个card之后,其他的person就不能使用该card 了。
代码如下:Card
`
package org.fkit.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();
// TODO Auto-generated constructor stub
}
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 + "]";
}
}
`
代码如下:Person
`
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();
// TODO Auto-generated constructor stub
}
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 + "]";
}
}
`
一对多
在实际项目开发中,一对多是非常常见的关系,比如,一个班级可以有多个学生,一个学 生只能属于一个班级,班级和学生是一对多的关系,而学生和班级是多对一的关系。数据库中 一对多关系通常使用主外键关联,外键列应该在多方,即多方维护关系。下面我们就用一个简单本例来看看MyBatis怎么处理一对多关系。
首先,给之前创建的mybatis数据库创建两个表tb_clazz和tb_student,并插入测试数据。 SQL脚本如下:
`
CREATE TABLE tb_clazz(
id INT PRIMARY KEY AUTO_INCREMENT,
CODE VARCHAR(18),
NAME VARCHAR(18)
);
INSERT INTO tb_clazz(CODE,NAME) VALUES('j1601','aaa');
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('jack','男',23,1);
INSERT INTO tb_student(NAME,sex,age,clazz_id) VALUES('rose','女',18,1);
INSERT INTO tb_student(NAME,sex,age,clazz_id) VALUES('tom','男',21,1);
INSERT INTO tb_student(NAME,sex,age,clazz_id) VALUES('alice','女',20,1);
`
tb_student表的clazz_id作为外键参 照tb_clazz表的主键id。
Clazz实体:
`
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();
// TODO Auto-generated constructor stub
}
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 + "]";
}
}
`
Student实体:
`
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();
// TODO Auto-generated constructor stub
}
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 + "]";
}
}
`
多对多
在实际项目开发中,多对多关系也是非常常见的关系,比如,一个购物系统中,一个用户 可以有多个订单,这是一对多的关系;一个订单中可以购买多种商品,一种商品也可以属于多 个不同的订单,订单和商品就是多对多的关系。对于数据库中多对多关系建议使用一个中间表 来维护关系,中间表中的订单id作为外键参照订单表的id,商品id作为外键参照商品表的id。 下面我们就用一个简单示例来看看MyBatis怎么处理多对多关系。
首先,给之前创建的mybatis数据库创建三个表tb_user、tb_article和tb_order, 再创建一个中间表维护tb_article和tb_order的关系,并插入测试数据。SQL脚本如下。
`
/**
*
CREATE TABLE tb_user(
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(18),
loginname VARCHAR(18),
PASSWORD VARCHAR(18),
phone VARCHAR(18),
address VARCHAR(18)
);
INSERT INTO tb_user(username,loginname,PASSWORD,phone,address)
VALUES('杰克','jack','123456','1392456789','广州');
CREATE TABLE tb_article(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(18),
price DOUBLE,
remark VARCHAR(18)
);
INSERT INTO tb_article(NAME,price,remark)
VALUES('aaa',108.9,'aaa经典著作');
INSERT INTO tb_article(NAME,price,remark)
VALUES('bbb',99.9,'bbb经典著作');
INSERT INTO tb_article(NAME,price,remark)
VALUES('ccc',89.9,'ccc经典著作');
INSERT INTO tb_article(NAME,price,remark)
VALUES('ddd',69.9,'ddd经典著作');
CREATE TABLE tb_order(
id INT PRIMARY KEY AUTO_INCREMENT,
CODE VARCHAR(32),
total DOUBLE,
user_id INT,
FOREIGN KEY (user_id) REFERENCES tb_user(id)
);
INSERT INTO tb_order(CODE,total,user_id)
VALUES('6aa3fa359ff14619b77fab5990940a2d',388.6,1);
INSERT INTO tb_order(CODE,total,user_id)
VALUES('6aa3fa359ff14619b77fab5990940b3c',217.8,1);
CREATE TABLE tb_item(
order_id INT,
article_id INT,
amount INT,
PRIMARY KEY(order_id,article_id),
FOREIGN KEY (order_id) REFERENCES tb_order(id),
FOREIGN KEY (article_id) REFERENCES tb_article(id)
);
INSERT INTO tb_item(order_id,article_id,amount)
VALUES(1,1,1);
INSERT INTO tb_item(order_id,article_id,amount)
VALUES(1,2,1);
INSERT INTO tb_item(order_id,article_id,amount)
VALUES(1,3,2);
INSERT INTO tb_item(order_id,article_id,amount)
VALUES(2,4,2);
INSERT INTO tb_item(order_id,article_id,amount)
VALUES(2,1,1);
* */``
`
实体:User
`
public class User implements Serializable{
private static final long serialVersionUID = 1L;
private Integer id; // 用户id,主键
private String username; // 用户名
private String loginname; // 登录名
private String password; // 密码
private String phone; // 联系电话
private String address; // 收货地址
// 用户和订单是一对多的关系,即一个用户可以有多个订单
private List orders;
public User() {
super();
// TODO Auto-generated constructor stub
}
public User(String username, String loginname, String password,
String phone, String address) {
super();
this.username = username;
this.loginname = loginname;
this.password = password;
this.phone = phone;
this.address = address;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getLoginname() {
return loginname;
}
public void setLoginname(String loginname) {
this.loginname = loginname;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public List getOrders() {
return orders;
}
public void setOrders(List orders) {
this.orders = orders;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", loginname="
+ loginname + ", password=" + password + ", phone=" + phone
+ ", address=" + address + "]";
}
}
`
实体:Order
`
public class Order implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id; // 订单id,主键
private String code; // 订单编号
private Double total; // 订单总金额
// 订单和用户是多对一的关系,即一个订单只属于一个用户
private User user;
// 订单和商品是多对多的关系,即一个订单可以包含多种商品
private List articles;
public Order() {
super();
// TODO Auto-generated constructor stub
}
public Order(String code, Double total) {
super();
this.code = code;
this.total = total;
}
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 Double getTotal() {
return total;
}
public void setTotal(Double total) {
this.total = total;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public List getArticles() {
return articles;
}
public void setArticles(List articles) {
this.articles = articles;
}
@Override
public String toString() {
return "Order [id=" + id + ", code=" + code + ", total=" + total + "]";
}
}
`
实体:Article
`
public class Article implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id; // 商品id,主键
private String name; // 商品名称
private Double price; // 商品价格
private String remark; // 商品描述
// 商品和订单是多对多的关系,即一种商品可以包含在多个订单中
private List orders;
public Article() {
super();
// TODO Auto-generated constructor stub
}
public Article(String name, Double price, String remark) {
super();
this.name = name;
this.price = price;
this.remark = remark;
}
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 Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public List getOrders() {
return orders;
}
public void setOrders(List orders) {
this.orders = orders;
}
@Override
public String toString() {
return "Article [id=" + id + ", name=" + name + ", price=" + price
+ ", remark=" + remark + "]";
}
}
`
tb_order表的user_id作为外键参照tb_user表的主键id。tb_item表作为中间表, 用来维护tb_article和tb_order的多对多关系,tb_imte表的order_id作为外键参照 tb_order表的主键id, article id作为外键参照tb article表的主键id
- 邮箱:[email protected]
- 技术讨论群:687856230
- GoodLuck