Spring Data 最佳实践
ORM的出现解决了程序猿学习数据库学历成本,也加快了开发的速度。程序猿无需再学习数据库定义语言DDL以及数据库客户端,也无需关注建表这些繁琐的工作,同时也降低了数据库结构变更管理中与DBA频繁沟通的成本。。
在过去的两年中我们采用 Spring Data JPA 定义数据库,访问数据库,积累了很多经验,最终我们发现使用 Spring Data 实体定义完全可以代替 DBA 的建模工作。
下面我们采用案例,一个一个讲解,各种数据库实体关系的定义。相关数据库建模知识请先阅读 《Netkiller Architect 手札》 以及 《Netkiller Spring 手札》
分类表
这是一个通用分类表,常见的父子关系加上path路径
+-----------+ | category | |-----------| |id | <---+ |name | | |description| 1:n |status | | |pid | o---+ |path | |status | |ctime | |mtime | +-----------+
package cn.netkiller.domain; import java.util.Date; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import org.springframework.format.annotation.DateTimeFormat; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnore; @Entity public class Category { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", unique = true, nullable = false, insertable = true, updatable = false) public int id; public String name; public String description; public String path; @Column(columnDefinition = "enum('Enabled','Disabled') DEFAULT 'Enabled' COMMENT '状态'") public String 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 '创建时间'") public Date 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 '更改时间'") public Date mtime; @ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.REMOVE }) @JoinColumn(name = "pid", referencedColumnName = "id") private Category categorys; @JsonIgnore @OneToMany(cascade = CascadeType.ALL, mappedBy = "category", fetch = FetchType.EAGER) private Set<Category> category; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public Date getCtime() { return ctime; } public void setCtime(Date ctime) { this.ctime = ctime; } public Date getMtime() { return mtime; } public void setMtime(Date mtime) { this.mtime = mtime; } public Category getCategorys() { return categorys; } public void setCategorys(Category categorys) { this.categorys = categorys; } public Set<Category> getCategory() { return category; } public void setCategory(Set<Category> category) { this.category = category; } @Override public String toString() { return "Category [id=" + id + ", name=" + name + ", description=" + description + ", path=" + path + ", status=" + status + ", ctime=" + ctime + ", mtime=" + mtime + ", categorys=" + categorys + ", category=" + category + "]"; } }
期望结果
CREATE TABLE `category` ( `id` int(11) NOT NULL AUTO_INCREMENT, `ctime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '', `description` varchar(255) DEFAULT NULL, `mtime` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '', `name` varchar(255) DEFAULT NULL, `path` varchar(255) DEFAULT NULL, `status` enum('Enabled','Disabled') DEFAULT 'Enabled' COMMENT '', `pid` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8
为字段增加索引
我们希望为 name 和 path 字段增加普通索引
package cn.netkiller.domain; import java.util.Date; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Index; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.Table; import org.springframework.format.annotation.DateTimeFormat; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnore; @Entity @Table(indexes = { @Index(name = "name", columnList = "name DESC"), @Index(name = "path", columnList = "path") }) public class Category { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", unique = true, nullable = false, insertable = true, updatable = false) public int id; public String name; public String description; public String path; @Column(columnDefinition = "enum('Enabled','Disabled') DEFAULT 'Enabled' COMMENT '状态'") public String 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 '创建时间'") public Date 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 '更改时间'") public Date mtime; @ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.REMOVE }) @JoinColumn(name = "pid", referencedColumnName = "id") private Categ