首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Spring Data 最佳实践

摘要: ORM的出现解决了程序猿学习数据库学历成本,也加快了开发的速度。程序猿无需再学习数据库定义语言DDL以及数据库客户端,也无需关注建表这些繁琐的工作,同时也降低了数据库结构变更管理中与DBA频繁沟通的成本。

本文节选自电子书《Netkiller Architect 手札》

第 12 章 Spring Data 最佳实践

目录

12.1. 分类表

12.2. 为字段增加索引

12.3. 复合索引

12.4. 一对多实例

12.5. ManyToMany 多对多

12.6. 外键级联删除

ORM的出现解决了程序猿学习数据库学历成本,也加快了开发的速度。程序猿无需再学习数据库定义语言DDL以及数据库客户端,也无需关注建表这些繁琐的工作,同时也降低了数据库结构变更管理中与DBA频繁沟通的成本。。

在过去的两年中我们采用 Spring Data JPA 定义数据库,访问数据库,积累了很多经验,最终我们发现使用 Spring Data 实体定义完全可以代替 DBA 的建模工作。

下面我们采用案例,一个一个讲解,各种数据库实体关系的定义。相关数据库建模知识请先阅读 《Netkiller Architect 手札》 以及 《Netkiller Spring 手札》

12.1. 分类表

这是一个通用分类表,常见的父子关系加上path路径

+-----------+category-----------id

packagecn.netkiller.domain;importjava.util.Date;importjava.util.Set;importjavax.persistence.CascadeType;importjavax.persistence.Column;importjavax.persistence.Entity;importjavax.persistence.FetchType;importjavax.persistence.GeneratedValue;importjavax.persistence.GenerationType;importjavax.persistence.Id;importjavax.persistence.JoinColumn;importjavax.persistence.ManyToOne;importjavax.persistence.OneToMany;importorg.springframework.format.annotation.DateTimeFormat;importcom.fasterxml.jackson.annotation.JsonFormat;importcom.fasterxml.jackson.annotation.JsonIgnore;@EntitypublicclassCategory{@Id@GeneratedValue(strategy = GenerationType.IDENTITY)@Column(name ="id", unique =true, nullable =false, insertable =true, updatable =false)publicintid;publicString name;publicString description;publicString path;@Column(columnDefinition ="enum('Enabled','Disabled') DEFAULT 'Enabled' COMMENT '状态'")publicString status;@DateTimeFormat(pattern ="yyyy-MM-dd HH:mm:ss")@JsonFormat(pattern ="yyyy-MM-dd HH:mm:ss", timezone ="GMT+8")@Column(columnDefinition ="TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'")publicDate ctime;@DateTimeFormat(pattern ="yyyy-MM-dd HH:mm:ss")@JsonFormat(pattern ="yyyy-MM-dd HH:mm:ss", timezone ="GMT+8")@Column(columnDefinition ="TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更改时间'")publicDate mtime;@ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.REMOVE })@JoinColumn(name ="pid", referencedColumnName ="id")privateCategory categorys;@JsonIgnore@OneToMany(cascade = CascadeType.ALL, mappedBy ="category", fetch = FetchType.EAGER)privateSet category;publicintgetId(){returnid;}publicvoidsetId(intid){this.id = id;}publicStringgetName(){returnname;}publicvoidsetName(String name){this.name = name;}publicStringgetDescription(){returndescription;}publicvoidsetDescription(String description){this.description = description;}publicStringgetPath(){returnpath;}publicvoidsetPath(String path){this.path = path;}publicStringgetStatus(){returnstatus;}publicvoidsetStatus(String status){this.status = status;}publicDategetCtime(){returnctime;}publicvoidsetCtime(Date ctime){this.ctime = ctime;}publicDategetMtime(){returnmtime;}publicvoidsetMtime(Date mtime){this.mtime = mtime;}publicCategorygetCategorys(){returncategorys;}publicvoidsetCategorys(Category categorys){this.categorys = categorys;}publicSetgetCategory(){returncategory;}publicvoidsetCategory(Set category){this.category = category;}@OverridepublicStringtoString(){return"Category [id="+ id +", name="+ name +", description="+ description +", path="+ path +", status="+ status +", ctime="+ ctime +", mtime="+ mtime +", categorys="+ categorys +", category="+ category +"]";}}

期望结果

CREATETABLE`category`(`id`int(11)NOTNULLAUTO_INCREMENT,`ctime`timestampNOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT'',`description`varchar(255)DEFAULTNULL,`mtime`timestampNULLDEFAULTNULLONUPDATECURRENT_TIMESTAMPCOMMENT'',`name`varchar(255)DEFAULTNULL,`path`varchar(255)DEFAULTNULL,`status`enum('Enabled','Disabled')DEFAULT'Enabled'COMMENT'',`pid`int(11)DEFAULTNULL, PRIMARYKEY(`id`))ENGINE=InnoDBDEFAULTCHARSET=utf8

12.2. 为字段增加索引

我们希望为 name 和 path 字段增加普通索引

packagenetkiller.domain;importjava.util.Date;importjava.util.Set;importjavax.persistence.CascadeType;importjavax.persistence.Column;importjavax.persistence.Entity;importjavax.persistence.FetchType;importjavax.persistence.GeneratedValue;importjavax.persistence.GenerationType;importjavax.persistence.Id;importjavax.persistence.Index;importjavax.persistence.JoinColumn;importjavax.persistence.ManyToOne;importjavax.persistence.OneToMany;importjavax.persistence.Table;importorg.springframework.format.annotation.DateTimeFormat;importcom.fasterxml.jackson.annotation.JsonFormat;importcom.fasterxml.jackson.annotation.JsonIgnore;@Entity@Table(indexes = {@Index(name ="name", columnList ="name DESC"),@Index(name ="path", columnList ="path") })publicclassCategory{@Id@GeneratedValue(strategy = GenerationType.IDENTITY)@Column(name ="id", unique =true, nullable =false, insertable =true, updatable =false)publicintid;publicString name;publicString description;publicString path;@Column(columnDefinition ="enum('Enabled','Disabled') DEFAULT 'Enabled' COMMENT '状态'")publicString status;@DateTimeFormat(pattern ="yyyy-MM-dd HH:mm:ss")@JsonFormat(pattern ="yyyy-MM-dd HH:mm:ss", timezone ="GMT+8")@Column(columnDefinition ="TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'")publicDate ctime;@DateTimeFormat(pattern ="yyyy-MM-dd HH:mm:ss")@JsonFormat(pattern ="yyyy-MM-dd HH:mm:ss", timezone ="GMT+8")@Column(columnDefinition ="TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更改时间'")publicDate mtime;@ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.REMOVE })@JoinColumn(name ="pid", referencedColumnName ="id")privateCategory categorys;@JsonIgnore@OneToMany(cascade = CascadeType.ALL, mappedBy ="category", fetch = FetchType.EAGER)privateSet category;publicintgetId(){returnid;}publicvoidsetId(intid){this.id = id;}publicStringgetName(){returnname;}publicvoidsetName(String name){this.name = name;}publicStringgetDescription(){returndescription;}publicvoidsetDescription(String description){this.description = description;}publicStringgetPath(){returnpath;}publicvoidsetPath(String path){this.path = path;}publicStringgetStatus(){returnstatus;}publicvoidsetStatus(String status){this.status = status;}publicDategetCtime(){returnctime;}publicvoidsetCtime(Date ctime){this.ctime = ctime;}publicDategetMtime(){returnmtime;}publicvoidsetMtime(Date mtime){this.mtime = mtime;}publicCategorygetCategorys(){returncategorys;}publicvoidsetCategorys(Category categorys){this.categorys = categorys;}publicSetgetCategory(){returncategory;}publicvoidsetCategory(Set category){this.category = category;}@OverridepublicStringtoString(){return"Category [id="+ id +", name="+ name +", description="+ description +", path="+ path +", status="+ status +", ctime="+ ctime +", mtime="+ mtime +", categorys="+ categorys +", category="+ category +"]";}}

期望结果

CREATETABLE`category`(`id`int(11)NOTNULLAUTO_INCREMENT,`ctime`timestampNOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT'????',`description`varchar(255)DEFAULTNULL,`mtime`timestampNULLDEFAULTNULLONUPDATECURRENT_TIMESTAMPCOMMENT'????',`name`varchar(255)DEFAULTNULL,`path`varchar(255)DEFAULTNULL,`status`enum('Enabled','Disabled')DEFAULT'Enabled'COMMENT'??',`pid`int(11)DEFAULTNULL, PRIMARYKEY(`id`),KEY`name`(`name`),KEY`path`(`path`),KEY`FKeiel7nqjxu4kmefso9tm9qcsu`(`pid`),CONSTRAINT`FKeiel7nqjxu4kmefso9tm9qcsu`FOREIGNKEY(`pid`)REFERENCES`category`(`id`))ENGINE=InnoDBDEFAULTCHARSET=utf8

12.3. 复合索引

创建由多个字段组成的复合索引,如: "member_id", "articleId"

packagecn.netkiller.api.model;importjava.io.Serializable;importjava.util.Date;importjavax.persistence.CascadeType;importjavax.persistence.Column;importjavax.persistence.Entity;importjavax.persistence.GeneratedValue;importjavax.persistence.GenerationType;importjavax.persistence.Id;importjavax.persistence.JoinColumn;importjavax.persistence.ManyToOne;importjavax.persistence.Table;importjavax.persistence.Temporal;importjavax.persistence.TemporalType;importjavax.persistence.UniqueConstraint;importcom.fasterxml.jackson.annotation.JsonFormat;@Entity@Table(name ="comment", uniqueConstraints = {@UniqueConstraint(columnNames = {"member_id","articleId"}) })publicclassCommentimplementsSerializable{/** * */privatestaticfinallongserialVersionUID = -1484408775034277681L;@Id@GeneratedValue(strategy = GenerationType.IDENTITY)@Column(name ="id", unique =true, nullable =false, insertable =true, updatable =false)privateintid;@ManyToOne(cascade = { CascadeType.ALL })@JoinColumn(name ="member_id")privateMember member;privateintarticleId;privateString message;@JsonFormat(pattern ="yyyy-MM-dd HH:mm:ss")@Temporal(TemporalType.TIMESTAMP)@Column(updatable =false)@org.hibernate.annotations.CreationTimestampprotectedDate createDate;publicintgetId(){returnid;}publicvoidsetId(intid){this.id = id;}publicMembergetMember(){returnmember;}publicvoidsetMember(Member member){this.member = member;}publicintgetArticleId(){returnarticleId;}publicvoidsetArticleId(intarticleId){this.articleId = articleId;}publicStringgetMessage(){returnmessage;}publicvoidsetMessage(String message){this.message = message;}publicDategetCreateDate(){returncreateDate;}publicvoidsetCreateDate(Date createDate){this.createDate = createDate;}}

期望结果

CREATETABLE`comment`(`id`int(11)NOTNULLAUTO_INCREMENT,`article_id`int(11)NOTNULL,`create_date`datetimeDEFAULTNULL,`message`varchar(255)DEFAULTNULL,`member_id`int(11)DEFAULTNULL, PRIMARYKEY(`id`),UNIQUEKEY`UK5qxfiu92nwlvgli7bl3evl11m`(`member_id`,`article_id`),CONSTRAINT`FKmrrrpi513ssu63i2783jyiv9m`FOREIGNKEY(`member_id`)REFERENCES`member`(`id`))ENGINE=InnoDBDEFAULTCHARSET=utf8;

12.4. 一对多实例

如下图,我们将实现 categroy 和 article 的一对多关系

+-----------+category-----------+-->idid

首先定义分类实体类

packagecn.netkiller.domain;importjava.util.Date;importjava.util.Set;importjavax.persistence.CascadeType;importjavax.persistence.Column;importjavax.persistence.Entity;importjavax.persistence.FetchType;importjavax.persistence.GeneratedValue;importjavax.persistence.GenerationType;importjavax.persistence.Id;importjavax.persistence.Index;importjavax.persistence.JoinColumn;importjavax.persistence.ManyToOne;importjavax.persistence.OneToMany;importjavax.persistence.Table;importorg.springframework.format.annotation.DateTimeFormat;importcom.fasterxml.jackson.annotation.JsonFormat;importcom.fasterxml.jackson.annotation.JsonIgnore;@Entity@Table(indexes = {@Index(name ="name", columnList ="name DESC"),@Index(name ="path", columnList ="path") })publicclassCategory{@Id@GeneratedValue(strategy = GenerationType.IDENTITY)@Column(name ="id", unique =true, nullable =false, insertable =true, updatable =false)publicintid;publicString name;publicString description;publicString path;@Column(columnDefinition ="enum('Enabled','Disabled') DEFAULT 'Enabled' COMMENT '状态'")publicString status;@DateTimeFormat(pattern ="yyyy-MM-dd HH:mm:ss")@JsonFormat(pattern ="yyyy-MM-dd HH:mm:ss", timezone ="GMT+8")@Column(columnDefinition ="TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'")publicDate ctime;@DateTimeFormat(pattern ="yyyy-MM-dd HH:mm:ss")@JsonFormat(pattern ="yyyy-MM-dd HH:mm:ss", timezone ="GMT+8")@Column(columnDefinition ="TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更改时间'")publicDate mtime;@ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.REMOVE })@JoinColumn(name ="pid", referencedColumnName ="id")privateCategory categorys;@JsonIgnore@OneToMany(cascade = CascadeType.ALL, mappedBy ="category", fetch = FetchType.EAGER)privateSet category;@JsonIgnore@OneToMany(cascade = CascadeType.ALL, mappedBy ="category", orphanRemoval =true)privateSet article;publicintgetId(){returnid;}publicvoidsetId(intid){this.id = id;}publicStringgetName(){returnname;}publicvoidsetName(String name){this.name = name;}publicStringgetDescription(){returndescription;}publicvoidsetDescription(String description){this.description = description;}publicStringgetPath(){returnpath;}publicvoidsetPath(String path){this.path = path;}publicStringgetStatus(){returnstatus;}publicvoidsetStatus(String status){this.status = status;}publicDategetCtime(){returnctime;}publicvoidsetCtime(Date ctime){this.ctime = ctime;}publicDategetMtime(){returnmtime;}publicvoidsetMtime(Date mtime){this.mtime = mtime;}publicCategorygetCategorys(){returncategorys;}publicvoidsetCategorys(Category categorys){this.categorys = categorys;}publicSetgetCategory(){returncategory;}publicvoidsetCategory(Set category){this.category = category;}@OverridepublicStringtoString(){return"Category [id="+ id +", name="+ name +", description="+ description +", path="+ path +", status="+ status +", ctime="+ ctime +", mtime="+ mtime +", categorys="+ categorys +", category="+ category +"]";}}

定义文章实体类

packagecn.netkiller.domain;importjava.io.Serializable;importjava.util.Date;importjava.util.Set;importjavax.persistence.CascadeType;importjavax.persistence.Column;importjavax.persistence.Entity;importjavax.persistence.FetchType;importjavax.persistence.GeneratedValue;importjavax.persistence.GenerationType;importjavax.persistence.Id;importjavax.persistence.JoinColumn;importjavax.persistence.ManyToOne;importjavax.persistence.OneToMany;importjavax.persistence.Table;importorg.springframework.format.annotation.DateTimeFormat;importcom.fasterxml.jackson.annotation.JsonFormat;importcom.fasterxml.jackson.annotation.JsonIgnore;@Entity@Table(name ="article")publicclassArticleimplementsSerializable{privatestaticfinallongserialVersionUID =7603772682950271321L;@Id@GeneratedValue(strategy = GenerationType.IDENTITY)@Column(name ="id", unique =true, nullable =false, insertable =true, updatable =false)publicintid;publicString title;@Column(name ="short")publicString shortTitle;publicString description;publicString author;publicintstar;publicString tag;publicbooleanshare;publicbooleanstatus;publicString content;@ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.REMOVE })@JoinColumn(name ="category_id", referencedColumnName ="id")privateCategory category;@ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.REMOVE })@JoinColumn(name ="site_id", referencedColumnName ="id")privateSite site;@ManyToOne(cascade = { CascadeType.ALL })@JoinColumn(name ="member_id", referencedColumnName ="id")privateMember member;@DateTimeFormat(pattern ="yyyy-MM-dd HH:mm:ss")@JsonFormat(pattern ="yyyy-MM-dd HH:mm:ss", timezone ="GMT+8")@Column(columnDefinition ="TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'")publicDate ctime;@DateTimeFormat(pattern ="yyyy-MM-dd HH:mm:ss")@JsonFormat(pattern ="yyyy-MM-dd HH:mm:ss", timezone ="GMT+8")@Column(columnDefinition ="TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更改时间'")publicDate mtime;@JsonIgnore@OneToMany(cascade = CascadeType.ALL, mappedBy ="article", fetch = FetchType.EAGER)privateSet comment;@JsonIgnore@OneToMany(cascade = CascadeType.ALL, mappedBy ="article", fetch = FetchType.EAGER)privateSet favorites;@JsonIgnore@OneToMany(cascade = CascadeType.ALL, mappedBy ="article", orphanRemoval =true)privateSet statistics;publicintgetId(){returnid;}publicvoidsetId(intid){this.id = id;}publicStringgetTitle(){returntitle;}publicvoidsetTitle(String title){this.title = title;}publicStringgetDescription(){returndescription;}publicvoidsetDescription(String description){this.description = description;}publicDategetCtime(){returnctime;}publicvoidsetCtime(Date ctime){this.ctime = ctime;}publicStringgetShortTitle(){returnshortTitle;}publicvoidsetShortTitle(String shortTitle){this.shortTitle = shortTitle;}publicStringgetAuthor(){returnauthor;}publicvoidsetAuthor(String author){this.author = author;}publicintgetStar(){returnstar;}publicvoidsetStar(intstar){this.star = star;}publicStringgetTag(){returntag;}publicvoidsetTag(String tag){this.tag = tag;}publicbooleanisShare(){returnshare;}publicvoidsetShare(booleanshare){this.share = share;}publicbooleanisStatus(){returnstatus;}publicvoidsetStatus(booleanstatus){this.status = status;}publicStringgetContent(){returncontent;}publicvoidsetContent(String content){this.content = content;}publicCategorygetCategory(){returncategory;}publicvoidsetCategory(Category category){this.category = category;}publicMembergetMember(){returnmember;}publicvoidsetMember(Member member){this.member = member;}publicSetgetComment(){returncomment;}publicvoidsetComment(Set comment){this.comment = comment;}publicSetgetFavorites(){returnfavorites;}publicvoidsetFavorites(Set favorites){this.favorites = favorites;}publicSetgetStatistics(){returnstatistics;}publicvoidsetStatistics(Set statistics){this.statistics = statistics;}publicSitegetSite(){returnsite;}publicvoidsetSite(Site site){this.site = site;}publicDategetMtime(){returnmtime;}publicvoidsetMtime(Date mtime){this.mtime = mtime;}@OverridepublicStringtoString(){return"Article [id="+ id +", title="+ title +", shortTitle="+ shortTitle +", description="+ description+", author="+ author +", star="+ star +", tag="+ tag +", share="+ share +", status="+ status+", content="+ content +", category="+ category +", site="+ site +", member="+ member+", ctime="+ ctime +", mtime="+ mtime +", comment="+ comment +", favorites="+ favorites+", statistics="+ statistics +"]";}}

希望结果

CREATETABLE`category`(`id`int(11)NOTNULLAUTO_INCREMENT,`ctime`timestampNOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT'????',`description`varchar(255)DEFAULTNULL,`mtime`timestampNULLDEFAULTNULLONUPDATECURRENT_TIMESTAMPCOMMENT'????',`name`varchar(255)DEFAULTNULL,`path`varchar(255)DEFAULTNULL,`status`enum('Enabled','Disabled')DEFAULT'Enabled'COMMENT'??',`pid`int(11)DEFAULTNULL, PRIMARYKEY(`id`),KEY`name`(`name`),KEY`path`(`path`),KEY`FKeiel7nqjxu4kmefso9tm9qcsu`(`pid`),CONSTRAINT`FKeiel7nqjxu4kmefso9tm9qcsu`FOREIGNKEY(`pid`)REFERENCES`category`(`id`))ENGINE=InnoDBDEFAULTCHARSET=utf8;CREATETABLE`article`(`id`int(11)NOTNULLAUTO_INCREMENT,`author`varchar(255)DEFAULTNULL,`content`varchar(255)DEFAULTNULL,`ctime`timestampNOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT'????',`description`varchar(255)DEFAULTNULL,`mtime`timestampNULLDEFAULTNULLONUPDATECURRENT_TIMESTAMPCOMMENT'????',`share`bit(1)NOTNULL,`short`varchar(255)DEFAULTNULL,`star`int(11)NOTNULL,`status`bit(1)NOTNULL,`tag`varchar(255)DEFAULTNULL,`title`varchar(255)DEFAULTNULL,`category_id`int(11)DEFAULTNULL,`member_id`int(11)DEFAULTNULL,`site_id`int(11)DEFAULTNULL, PRIMARYKEY(`id`),KEY`FKy5kkohbk00g0w88fi05k2hcw`(`category_id`),KEY`FK6l9vkfd5ixw8o8kph5rj1k7gu`(`member_id`),KEY`FKrxbc33rok9m4n6pnbbwb3piwf`(`site_id`),CONSTRAINT`FK6l9vkfd5ixw8o8kph5rj1k7gu`FOREIGNKEY(`member_id`)REFERENCES`member`(`id`),CONSTRAINT`FKrxbc33rok9m4n6pnbbwb3piwf`FOREIGNKEY(`site_id`)REFERENCES`site`(`id`),CONSTRAINT`FKy5kkohbk00g0w88fi05k2hcw`FOREIGNKEY(`category_id`)REFERENCES`category`(`id`))ENGINE=InnoDBDEFAULTCHARSET=utf8;

现在我们已经将 categroy 与 article 两张表一对多关系建立起来。

12.5. ManyToMany 多对多

用户与角色就是一个多对多的关系,多对多是需要中间表做关联的。所以需要一个 user_has_role 表。

+----------+ +---------------+ +--------+usersuser_has_rolerole+----------+ +---------------+ +--------+ididnamerole_ido---+namepassword+----------+ +---------------+ +--------+

创建 User 表

packagecn.netkiller.api.domain.test;importjava.io.Serializable;importjava.util.Set;importjavax.persistence.Entity;importjavax.persistence.FetchType;importjavax.persistence.GeneratedValue;importjavax.persistence.GenerationType;importjavax.persistence.Id;importjavax.persistence.JoinTable;importjavax.persistence.ManyToMany;importjavax.persistence.Table;importjavax.persistence.JoinColumn;@Entity@Table(name ="users")publicclassUsersimplementsSerializable{/** * */privatestaticfinallongserialVersionUID = -2480194112597046349L;@Id@GeneratedValue(strategy = GenerationType.AUTO)privateintid;privateString name;privateString password;@ManyToMany(fetch = FetchType.EAGER)@JoinTable(name ="user_has_role", joinColumns = {@JoinColumn(name ="user_id", referencedColumnName ="id") }, inverseJoinColumns = {@JoinColumn(name ="role_id", referencedColumnName ="id") })privateSet roles;publicintgetId(){returnid;}publicvoidsetId(intid){this.id = id;}publicStringgetName(){returnname;}publicvoidsetName(String name){this.name = name;}publicStringgetPassword(){returnpassword;}publicvoidsetPassword(String password){this.password = password;}publicSetgetRoles(){returnroles;}publicvoidsetRoles(Set roles){this.roles = roles;}@OverridepublicStringtoString(){return"Users [id="+ id +", name="+ name +", password="+ password +", roles="+ roles +"]";}}

创建 Role 表

packagecn.netkiller.api.domain.test;importjava.io.Serializable;importjava.util.Set;importjavax.persistence.Entity;importjavax.persistence.GeneratedValue;importjavax.persistence.GenerationType;importjavax.persistence.Id;importjavax.persistence.ManyToMany;importjavax.persistence.Table;@Entity@Table(name ="roles")publicclassRolesimplementsSerializable{privatestaticfinallongserialVersionUID =6737037465677800326L;@Id@GeneratedValue(strategy = GenerationType.AUTO)privateintid;privateString name;@ManyToMany(mappedBy ="roles")privateSet users;publicintgetId(){returnid;}publicvoidsetId(intid){this.id = id;}publicStringgetName(){returnname;}publicvoidsetName(String name){this.name = name;}publicSetgetUsers(){returnusers;}publicvoidsetUsers(Set users){this.users = users;}@OverridepublicStringtoString(){return"Roles [id="+ id +", name="+ name +", users="+ users +"]";}}

最终产生数据库表如下

CREATETABLE`users`(`id`INT(11)NOTNULLAUTO_INCREMENT,`name`VARCHAR(255)NULLDEFAULTNULL,`password`VARCHAR(255)NULLDEFAULTNULL,PRIMARYKEY(`id`))COLLATE='utf8_general_ci'ENGINE=InnoDB;CREATETABLE`roles`(`id`INT(11)NOTNULLAUTO_INCREMENT,`name`VARCHAR(255)NULLDEFAULTNULL,PRIMARYKEY(`id`))COLLATE='utf8_general_ci'ENGINE=InnoDB;CREATETABLE`user_has_role`(`user_id`INT(11)NOTNULL,`role_id`INT(11)NOTNULL,PRIMARYKEY(`user_id`,`role_id`),INDEX`FKsvvq61v3koh04fycopbjx72hj`(`role_id`),CONSTRAINT`FK2dl1ftxlkldulcp934i3125qo`FOREIGNKEY(`user_id`)REFERENCES`users`(`id`),CONSTRAINT`FKsvvq61v3koh04fycopbjx72hj`FOREIGNKEY(`role_id`)REFERENCES`roles`(`id`))COLLATE='utf8_general_ci'ENGINE=InnoDB;

作者

转载请注明出处与作者声明

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20171221G062P400?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券