一、@OneToOne

  • 本例采用Master(用户实体)IDCARD(身份证实体)来描述一对一关系
  • 方式一: 实体通过外键关联到另一个实体的主键

    • Master.java

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      @Data
      @Entity
      @Table(name = "master")
      public class Master implements Serializable {

      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      @Column(name = "master_id")
      private long id;

      @Column(name = "pass_word")
      private String passWord;

      @Column(name = "real_name")
      private String realName;

      @Column(name = "user_name")
      private String userName;

      @Column(name = "gender")
      private String gender;

      /**
      * cascade = CascadeType.ALL : Master是关系的维护端(当删除master会级联删除idcard)
      * Master中的identity_id字段对应idcard表中的id字段
      */
      @OneToOne(cascade = CascadeType.ALL)
      @JoinColumn(name = "identity_id", referencedColumnName = "id")
      private Idcard idcard;
      }
    • Idcard.java

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      @Data
      @Entity
      @Table(name = "id_card")
      public class Idcard implements Serializable {

      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      @Column(name = "id")
      private long id;

      @Column(name = "NO")
      private String no;

      // 这里并不需要关联Master实体
      }
  • 方式二: 通过关联表

    • Master.java

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      @Data
      @Entity
      @Table(name = "master")
      public class Master implements Serializable {

      // 以上基本字段不变

      /**
      * cascade = CascadeType.ALL : Master是关系的维护端(当删除master会级联删除idcard)
      * name = "t_master_idcard" 为中间表的名称,并不需要提前创建 项目运行时会自动创建
      * joinColumns = @JoinColumn(name = "master_id") 为当前表在中间表的字段
      * inverseJoinColumns = @JoinColumn(name = "idcard_id") 为当前表的关联表在中间表的字段
      */
      @OneToOne(cascade = CascadeType.ALL)
      @JoinTable(name = "t_master_idcard", joinColumns = @JoinColumn(name = "master_id"), inverseJoinColumns = @JoinColumn(name = "idcard_id"))
      private Idcard idcard;
      }
    • Idcard.java(保持不变)

二、@OneToMany 和 @ManyToOne

  • 本例采用Brand(品牌实体)一方Mobile(手机实体)多方来描述一对多关系(双向)
  • Brand.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    @Data
    @Entity
    @Table(name = "brand")
    public class Brand implements Serializable {

    @Id
    @Column(name = "brand_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(name = "brand_name")
    private String name;

    @Column(name = "depict")
    private String depict;

    /**
    * mappedBy = "brand" 是mobile中brand属性,拥有mappedBy注解的实体类为关系被维护端
    * cascade = CascadeType.ALL(级联保存、更新、删除、刷新)
    * 特别注意cascade = CascadeType.ALL只能写在一方这端,只有One端改变Many端,不准Many端改变One端
    * fetch = FetchType.LAZY 延迟加载
    * 当删除手机品牌时,会级联删除该品牌的所有手机
    */
    @OneToMany(mappedBy = "brands", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private Collection<Mobile> mobileList;

    }
  • Mobile.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    @Data
    @Entity
    @Table(name = "mobile")
    public class Mobile implements Serializable {

    @Id
    @Column(name = "mobile_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @Column(name = "type")
    private String type;

    @Column(name = "os")
    private String os;

    @Column(name = "cpu")
    private String cpu;

    @Column(name = "ram_size")
    private Integer ramSize;

    @Column(name = "disk_size")
    private Integer diskSize;

    /**
    * cascade = CascadeType.PERSIST 设置级联操作 使之两边都添加
    * optional = false 删除手机不影响手机品牌
    * @JoinColumn(name = "brand_id") 设置mobile表的关联字段(为一方brand表的主键)
    */
    @ManyToOne(cascade = {CascadeType.MERGE, CascadeType.REFRESH}, optional = false)
    @JoinColumn(name = "brand_id")
    private Brand brands;
    }

三、@ManyToMany

  • 本例采用Master(用户实体)Authority(权限实体)来描述多对多关系
  • 注意点( 转自言曌博客 )
    • 可以随意指定一方为关系维护端
    • 多对多关系中一般不设置级联保存、级联删除、级联更新等操作
    • 多对多关系的绑定、解除都由关系维护端来完成
    • 如果Master和Authority已经建立了多对多的关系
      • 那么不能直接删除Authority,需要由Master解除关系后才能删除
      • 但是可以直接删除Master,因为它是关系维护端
      • 当删除Master是,会解除Master和Authority的关系,再删除 Authority
  • Master.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    @Data
    @Entity
    @Table(name = "master")
    public class Master implements Serializable {

    // 以上基本字段不变

    /**
    * 关系维护端,负责多对多关系的绑定和解除
    * name = "t_master_authority" 为中间表的名称,并不需要提前创建 项目运行时会自动创建
    * joinColumns = @JoinColumn(name = "master_id") 为当前表在中间表的字段
    * inverseJoinColumns = @JoinColumn(name = "authority_id") 为当前表的关联表在中间表的字段
    */
    @ManyToMany
    @JoinTable(name = "t_master_authority", joinColumns = @JoinColumn(name = "master_id"), inverseJoinColumns = @JoinColumn(name = "authority_id"))
    private Collection<Authority> authorities;

    }
  • Authority.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    @Data
    @Entity
    @Table(name = "authority")
    public class Authority implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private long id;

    @Column(name = "name")
    private String name;

    /**
    * 关联Master.java中 Collection<Authority> authorities字段
    */
    @ManyToMany(mappedBy = "authorities")
    private Collection<Master> masters;

    }

四、数据库SQL执行脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for authority
-- ----------------------------
DROP TABLE IF EXISTS `authority`;
CREATE TABLE `authority` (
`id` int(4) NOT NULL AUTO_INCREMENT,
`name` varchar(225) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of authority
-- ----------------------------
BEGIN;
INSERT INTO `authority` VALUES (1, '增加');
INSERT INTO `authority` VALUES (2, '修改');
INSERT INTO `authority` VALUES (3, '删除');
INSERT INTO `authority` VALUES (4, '查询');
COMMIT;

-- ----------------------------
-- Table structure for brand
-- ----------------------------
DROP TABLE IF EXISTS `brand`;
CREATE TABLE `brand` (
`brand_id` int(11) NOT NULL AUTO_INCREMENT,
`brand_name` varchar(255) DEFAULT NULL,
`depict` varchar(255) DEFAULT NULL,
PRIMARY KEY (`brand_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=106 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

-- ----------------------------
-- Records of brand
-- ----------------------------
BEGIN;
INSERT INTO `brand` VALUES (101, '苹果', '世界第一品牌');
INSERT INTO `brand` VALUES (102, '华为', '中国第一品牌');
INSERT INTO `brand` VALUES (103, '小米', '雷布斯的爱机');
COMMIT;

-- ----------------------------
-- Table structure for id_card
-- ----------------------------
DROP TABLE IF EXISTS `id_card`;
CREATE TABLE `id_card` (
`id` int(4) NOT NULL,
`master_id` int(4) NOT NULL,
`NO` varchar(225) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of id_card
-- ----------------------------
BEGIN;
INSERT INTO `id_card` VALUES (1, 1001, '620301197607294018');
INSERT INTO `id_card` VALUES (2, 1002, '341801198612236547');
INSERT INTO `id_card` VALUES (3, 1003, '410711198805010602');
COMMIT;

-- ----------------------------
-- Table structure for master
-- ----------------------------
DROP TABLE IF EXISTS `master`;
CREATE TABLE `master` (
`master_id` int(11) NOT NULL AUTO_INCREMENT,
`pass_word` varchar(255) DEFAULT NULL,
`real_name` varchar(255) DEFAULT NULL,
`user_name` varchar(255) DEFAULT NULL,
`gender` char(2) DEFAULT NULL,
PRIMARY KEY (`master_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1005 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

-- ----------------------------
-- Records of master
-- ----------------------------
BEGIN;
INSERT INTO `master` VALUES (1001, '123', '张三', 'user1', '男');
INSERT INTO `master` VALUES (1002, '123', '李四', 'user2', '男');
INSERT INTO `master` VALUES (1003, '123', '王五', 'user3', '女');
COMMIT;

-- ----------------------------
-- Table structure for mobile
-- ----------------------------
DROP TABLE IF EXISTS `mobile`;
CREATE TABLE `mobile` (
`mobile_id` int(11) NOT NULL AUTO_INCREMENT,
`brand_id` int(255) DEFAULT NULL,
`type` varchar(255) DEFAULT NULL,
`os` varchar(255) DEFAULT NULL,
`cpu` varchar(255) DEFAULT NULL,
`ram_size` int(11) DEFAULT NULL,
`disk_size` int(11) DEFAULT NULL,
PRIMARY KEY (`mobile_id`) USING BTREE,
KEY `FKokh4bde7qb9ocpems0iy71onu` (`brand_id`),
CONSTRAINT `FKokh4bde7qb9ocpems0iy71onu` FOREIGN KEY (`brand_id`) REFERENCES `brand` (`brand_id`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

-- ----------------------------
-- Records of mobile
-- ----------------------------
BEGIN;
INSERT INTO `mobile` VALUES (1, 101, 'Apple X', 'IOS', 'A12', 4, 64);
INSERT INTO `mobile` VALUES (2, 102, '华为Mate10', 'Android', '未知', 4, 128);
INSERT INTO `mobile` VALUES (3, 103, '小米8', 'Android', '高通 骁龙845', 6, 64);
COMMIT;