| 知乎专栏 |
@JoinColumn与@Column注释类似,它的定义如下代码所示。
@Target({METHOD, FIELD}) @Retention(RUNTIME)
public @interface JoinColumn {
String name() default "";
String referencedColumnName() default "";
boolean unique() default false;
boolean nullable() default true;
boolean insertable() default true;
boolean updatable() default true;
String columnDefinition() default "";
String table() default "";
}
定义外键名称 @ForeignKey(name = "picture_id")
@Id
@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "id", foreignKey = @ForeignKey(name = "picture_id"))
private Picture picture;
CREATE TABLE `picture_psychoanalysis` ( `analysis` text COMMENT '心里分析', `ctime` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `emotion` varchar(255) DEFAULT NULL COMMENT '感谢|愉快|抱怨|愤怒|喜爱|厌恶|恐惧|悲伤', `mtime` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', `replies` text COMMENT '建议回复话术', `sentiment` varchar(255) DEFAULT NULL COMMENT '负向情绪|中性情绪|正向情绪', `id` bigint unsigned NOT NULL, PRIMARY KEY (`id`), CONSTRAINT `picture_id` FOREIGN KEY (`id`) REFERENCES `picture` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='文生图心里分析'
一对一表结构,如下面ER图所示,users表是用户表里面有登陆信息,profile 保存的时死人信息,这样的目的是我们尽量减少users表的字段,在频繁操作该表的时候性能比较好,另外一个目的是为了横向水平扩展。
+----------+ +------------+
| users | | profile |
+----------+ +------------+
| id | <---1:1---o | id |
| name | | sex |
| password | | email |
+----------+ +------------+
package cn.netkiller.api.domain.test;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "users")
public class Users implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
private String password;
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 getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "Users [id=" + id + ", name=" + name + ", password=" + password + "]";
}
}
package cn.netkiller.api.domain.test;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name = "profile")
public class Profile implements Serializable {
/**
*
*/
private static final long serialVersionUID = -2500499458196257167L;
@Id
@OneToOne
@JoinColumn(name = "id")
private Users users;
private int age;
private String sex;
private String email;
public Users getUsers() {
return users;
}
public void setUsers(Users users) {
this.users = users;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "Profile [users=" + users + ", age=" + age + ", sex=" + sex + ", email=" + email + "]";
}
}
CREATE TABLE `users` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(255) NULL DEFAULT NULL, `password` VARCHAR(255) NULL DEFAULT NULL, PRIMARY KEY (`id`) ) COLLATE='utf8_general_ci' ENGINE=InnoDB; CREATE TABLE `profile` ( `age` INT(11) NOT NULL, `email` VARCHAR(255) NULL DEFAULT NULL, `sex` VARCHAR(255) NULL DEFAULT NULL, `id` INT(11) NOT NULL, PRIMARY KEY (`id`), CONSTRAINT `FK6x079ilawxjrfsljwyyi5ujjq` FOREIGN KEY (`id`) REFERENCES `users` (`id`) ) COLLATE='utf8_general_ci' ENGINE=InnoDB;
如果第二张表关联的并非主表的PK(主键)需要使用 referencedColumnName 指定。
@JoinColumn(name = "member_id",referencedColumnName="member_id")
package cn.netkiller.domain.demo;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String name;
}
package cn.netkiller.domain.demo;
import jakarta.persistence.*;
@Entity
public class BookDetail {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private long numberOfPages;
@OneToOne
private Book book;
}
CREATE TABLE `book` ( `id` bigint NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci CREATE TABLE `book_detail` ( `id` bigint NOT NULL AUTO_INCREMENT, `number_of_pages` bigint NOT NULL, `book_id` bigint DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `UK_29qtqq9pgixv8kqlt0woj1hyp` (`book_id`), CONSTRAINT `FKl1hmgccsvfwcxhem3qw6l7gpm` FOREIGN KEY (`book_id`) REFERENCES `book` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
package cn.netkiller.domain.demo;
import jakarta.persistence.*;
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String name;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "book_detail")
private BookDetail bookDetail;
}
package cn.netkiller.domain.demo;
import jakarta.persistence.*;
@Entity
public class BookDetail {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private long numberOfPages;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "bookDetail")
private Book book;
}
CREATE TABLE `book` ( `id` bigint NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `book_detail` bigint DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `UK_d8im4vqhlm2eo0mj9lwjvib94` (`book_detail`), CONSTRAINT `FKagqqxsh6783b9dd9197ow49a5` FOREIGN KEY (`book_detail`) REFERENCES `book_detail` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci CREATE TABLE `book_detail` ( `id` bigint NOT NULL AUTO_INCREMENT, `number_of_pages` bigint NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
package cn.netkiller.domain.demo;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class Users {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String name;
}
package cn.netkiller.domain.demo;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.OneToOne;
@Entity
public class Profile {
@Id
@OneToOne
private Users users;
private int age;
}
CREATE TABLE `users` ( `id` bigint NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci CREATE TABLE `profile` ( `age` int NOT NULL, `users_id` bigint NOT NULL, PRIMARY KEY (`users_id`), CONSTRAINT `FKi6d1noonlpe6oyk6pnwc1q49e` FOREIGN KEY (`users_id`) REFERENCES `users` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
指定一对一字段名,默认是表名+PK,例如上面的例子 users_id,如果我们希望自定义字段名,可以使用 @JoinColumn(name = "id")
package cn.netkiller.domain.demo;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne;
import lombok.Data;
@Entity
@Data
public class Profile {
@Id
@OneToOne
@JoinColumn(name = "id")
private Users users;
private int age;
private boolean sex;
}
效果展示
CREATE TABLE `profile` ( `age` int NOT NULL, `sex` bit(1) NOT NULL, `id` bigint NOT NULL, PRIMARY KEY (`id`), CONSTRAINT `FK6x079ilawxjrfsljwyyi5ujjq` FOREIGN KEY (`id`) REFERENCES `users` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
如果一对一的关系中,我们希望两端都是用 id 字段,而@OneToOne 一端是对象,必须定义一个 @Id,这时加入 @MapsId 可以解决 does not define an IdClass 错误,这时一段表中没有 @Id
package cn.netkiller.domain.demo;
import jakarta.persistence.*;
import lombok.Data;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
@Entity
@Table
@Data
@DynamicInsert
@DynamicUpdate
@Comment("用户表")
public class Users {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String username;
private String password;
private boolean status;
}
package cn.netkiller.domain.demo;
import jakarta.persistence.Table;
import jakarta.persistence.*;
import lombok.Data;
import org.hibernate.annotations.*;
@Entity
@Table
@Data
@DynamicInsert
@DynamicUpdate
@Comment("用户信息表")
public class Profile {
@Id
@Column(name = "id")
private Long id;
@MapsId
@OneToOne
@JoinColumn(name = "id")
@OnDelete(action = OnDeleteAction.CASCADE)
private Users users;
private int age;
private boolean sex;
}
package cn.netkiller.repository.demo;
import cn.netkiller.domain.demo.Profile;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface TestRepository extends JpaRepository<Profile, Long> {
}
CREATE TABLE `users` ( `id` bigint NOT NULL AUTO_INCREMENT, `password` varchar(255) DEFAULT NULL, `status` bit(1) NOT NULL, `username` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户表' CREATE TABLE `profile` ( `id` bigint NOT NULL, `age` int NOT NULL, `sex` bit(1) NOT NULL, PRIMARY KEY (`id`), CONSTRAINT `FK6x079ilawxjrfsljwyyi5ujjq` FOREIGN KEY (`id`) REFERENCES `users` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户信息表'
package cn.netkiller.domain.demo;
import jakarta.persistence.*;
import lombok.Data;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
@Entity
@Table
@Data
@DynamicInsert
@DynamicUpdate
@Comment("用户表")
public class Users {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String username;
private String password;
private boolean status;
@OneToOne(mappedBy = "users", cascade = CascadeType.ALL)
@PrimaryKeyJoinColumn
private Profile profile;
}
package cn.netkiller.domain.demo;
import jakarta.persistence.Table;
import jakarta.persistence.*;
import lombok.Data;
import org.hibernate.annotations.*;
@Entity
@Table
@Data
@DynamicInsert
@DynamicUpdate
@Comment("用户信息表")
public class Profile {
@Id
@Column(name = "id")
private Long id;
@MapsId
@OneToOne
@JoinColumn(name = "id")
@OnDelete(action = OnDeleteAction.CASCADE)
private Users users;
private int age;
private boolean sex;
}
CREATE TABLE `users` ( `id` bigint NOT NULL AUTO_INCREMENT, `password` varchar(255) DEFAULT NULL, `status` bit(1) NOT NULL, `username` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户表' CREATE TABLE `profile` ( `id` bigint NOT NULL, `age` int NOT NULL, `sex` bit(1) NOT NULL, PRIMARY KEY (`id`), CONSTRAINT `FK6x079ilawxjrfsljwyyi5ujjq` FOREIGN KEY (`id`) REFERENCES `users` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户信息表'
@OneToOne 保存提示 null identifier,经过排查需要配置
package cn.netkiller.domain;
import jakarta.persistence.CascadeType;
import jakarta.persistence.ForeignKey;
import jakarta.persistence.Table;
import jakarta.persistence.*;
import lombok.Data;
import org.hibernate.annotations.*;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
@Entity
@Table
@DynamicUpdate
@DynamicInsert
@Data
@Comment("文生图心里分析")
public class PicturePsychoanalysis implements Serializable {
@Serial
public static final long serialVersionUID = 1L;
@Comment("Robert Plutchik 情感轮盘")
@Column(columnDefinition = "json")
public String plutchik;
@Id
@Column(name = "id")
@Comment("Picture Id 一对一关系")
private Long id;
@MapsId
@OneToOne(cascade = CascadeType.MERGE)
@JoinColumn(name = "id", insertable = true, updatable = false, columnDefinition = "bigint unsigned", foreignKey = @ForeignKey(name = "picture_id"))
@OnDelete(action = OnDeleteAction.CASCADE)
private Picture picture;
@Comment("负向情绪|中性情绪|正向情绪")
private String sentiment;
@Comment("感谢|愉快|抱怨|愤怒|喜爱|厌恶|恐惧|悲伤")
private String emotion;
@Lob
@Basic(fetch = FetchType.LAZY)
@Column(nullable = true, columnDefinition = "text")
@Comment("建议回复话术")
private String replies;
@Lob
@Basic(fetch = FetchType.LAZY)
@Column(nullable = true, columnDefinition = "text")
@Comment("心里分析")
private String analysis;
// public JSONObject plutchik;
@Column(insertable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
@Comment("创建时间")
private Date ctime;
@Column(nullable = true, insertable = false, updatable = false, columnDefinition = "TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP")
@Comment("修改时间")
private Date mtime;
}
讲 @OneToOne 增加 @OneToOne(cascade = CascadeType.MERGE) 参数,如果 CascadeType.ALL 需要改为 CascadeType.MERGE
@Id
@Column(name = "id")
@Comment("Picture Id 一对一关系")
private Long id;
@MapsId
@OneToOne(cascade = CascadeType.MERGE)
@JoinColumn(name = "id", insertable = true, updatable = false, columnDefinition = "bigint unsigned", foreignKey = @ForeignKey(name = "picture_id"))
@OnDelete(action = OnDeleteAction.CASCADE)
private Picture picture;
我们要实现一个一对多实体关系,ER 图如下
+----------+ +------------+
| Classes | | Student |
+----------+ +------------+
| id | <---+ | id |
| name | | | name |
+----------+ +--o | classes_id |
+------------+
classes 表需要 OneToMany 注解,Student 表需要 ManyToOne 注解,这样就建立起了表与表之间的关系
package cn.netkiller.api.domain.test;
import java.io.Serializable;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name="classes")
public class Classes implements Serializable{
/**
*
*/
private static final long serialVersionUID = -5422905745519948312L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String name;
@OneToMany(cascade=CascadeType.ALL,mappedBy="classes")
private Set<Student> students;
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 Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
@Override
public String toString() {
return "classes [id=" + id + ", name=" + name + ", students=" + students + "]";
}
}
package cn.netkiller.api.domain.test;
import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name = "student")
public class Student implements Serializable{
/**
*
*/
private static final long serialVersionUID = 6737037465677800326L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
// 若有多个cascade,可以是:{CascadeType.PERSIST,CascadeType.MERGE}
@ManyToOne(cascade = { CascadeType.ALL })
@JoinColumn(name = "classes_id")
private Classes classes;
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 Classes getClasses() {
return classes;
}
public void setClasses(Classes classes) {
this.classes = classes;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", classes=" + classes + "]";
}
}
最终 SQL 表如下
CREATE TABLE `classes` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(255) NULL DEFAULT NULL, PRIMARY KEY (`id`) ) COLLATE='utf8_general_ci' ENGINE=InnoDB; CREATE TABLE `student` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(255) NULL DEFAULT NULL, `class_id` INT(11) NULL DEFAULT NULL, PRIMARY KEY (`id`), INDEX `FKnsl7w2nw6o6eq53hqlxfcijpm` (`class_id`), CONSTRAINT `FKnsl7w2nw6o6eq53hqlxfcijpm` FOREIGN KEY (`class_id`) REFERENCES `classes` (`id`) ) COLLATE='utf8_general_ci' ENGINE=InnoDB;
Classes classes=new Classes();
classes.setName("One");
Student st1=new Student();
st1.setSname("jason");
st1.setClasses(classes);
studentRepostitory.save(st1);
Student st2=new Student();
st2.setSname("neo");
st2.setClasses(classes);
studentRepostitory.save(st2);
用户与角色就是一个多对多的关系,多对多是需要中间表做关联的。所以我方需要一个 user_has_role 表。
+----------+ +---------------+ +--------+
| users | | user_has_role | | role |
+----------+ +---------------+ +--------+
| id | <------o | user_id | /---> | id |
| name | | role_id | o---+ | name |
| password | | | | |
+----------+ +---------------+ +--------+
创建 User 表
package cn.netkiller.api.domain.test;
import java.io.Serializable;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import javax.persistence.JoinColumn;
@Entity
@Table(name = "users")
public class Users implements Serializable {
/**
*
*/
private static final long serialVersionUID = -2480194112597046349L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
private String password;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "user_has_role", joinColumns = { @JoinColumn(name = "user_id", referencedColumnName = "id") }, inverseJoinColumns = { @JoinColumn(name = "role_id", referencedColumnName = "id") })
private Set<Roles> roles;
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 getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Set<Roles> getRoles() {
return roles;
}
public void setRoles(Set<Roles> roles) {
this.roles = roles;
}
@Override
public String toString() {
return "Users [id=" + id + ", name=" + name + ", password=" + password + ", roles=" + roles + "]";
}
}
创建 Role 表
package cn.netkiller.api.domain.test;
import java.io.Serializable;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
@Entity
@Table(name = "roles")
public class Roles implements Serializable {
private static final long serialVersionUID = 6737037465677800326L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
@ManyToMany(mappedBy = "roles")
private Set<Users> users;
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 Set<Users> getUsers() {
return users;
}
public void setUsers(Set<Users> users) {
this.users = users;
}
@Override
public String toString() {
return "Roles [id=" + id + ", name=" + name + ", users=" + users + "]";
}
}
最终产生数据库表如下
CREATE TABLE `users` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(255) NULL DEFAULT NULL, `password` VARCHAR(255) NULL DEFAULT NULL, PRIMARY KEY (`id`) ) COLLATE='utf8_general_ci' ENGINE=InnoDB; CREATE TABLE `roles` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(255) NULL DEFAULT NULL, PRIMARY KEY (`id`) ) COLLATE='utf8_general_ci' ENGINE=InnoDB; CREATE TABLE `user_has_role` ( `user_id` INT(11) NOT NULL, `role_id` INT(11) NOT NULL, PRIMARY KEY (`user_id`, `role_id`), INDEX `FKsvvq61v3koh04fycopbjx72hj` (`role_id`), CONSTRAINT `FK2dl1ftxlkldulcp934i3125qo` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`), CONSTRAINT `FKsvvq61v3koh04fycopbjx72hj` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ) COLLATE='utf8_general_ci' ENGINE=InnoDB;
orphanRemoval 是 JPA 定义,并不是数据库原生
@Id
@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "id", foreignKey = @ForeignKey(name = "picture_id"))
private Picture picture;
orphanRemoval = true 可以实现数据级联删除
package cn.netkiller.api.domain;
import java.io.Serializable;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonIgnore;
@Entity
@Table(name = "member")
public class Member implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", unique = true, nullable = false, insertable = true, updatable = false)
private int id;
private String name;
private String sex;
private int age;
private String wechat;
@Column(unique = true)
private String mobile;
private String picture;
private String ipAddress;
@JsonIgnore
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "member")
private Set<Comment> comment;
@JsonIgnore
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "member")
private Set<StatisticsHistory> statisticsHistory;
public Member() {
}
public Member(int id) {
this.id = id;
}
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 getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getWechat() {
return wechat;
}
public void setWechat(String wechat) {
this.wechat = wechat;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public String getPicture() {
return picture;
}
public void setPicture(String picture) {
this.picture = picture;
}
public String getIpAddress() {
return ipAddress;
}
public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
}
@Override
public String toString() {
return "Member [id=" + id + ", name=" + name + ", sex=" + sex + ", age=" + age + ", wechat=" + wechat + ", mobile=" + mobile + ", picture=" + picture + ", ipAddress=" + ipAddress + "]";
}
}
cascade 属性: 指定级联操作的行为(可多选)
CascadeType.PERSIST:级联新增(又称级联保存):对A对象保存时也会对B对象进行保存。并且,只有A类新增时,会级联B对象新增。若B对象在数据库存在则抛异常。对应EntityManager的presist方法。 CascadeType.MERGE:级联合并(级联更新):指A类新增或者变化,会级联B对象(新增或者变化)。对应EntityManager的merge方法。 CascadeType.REMOVE:级联删除:只有A类删除时,会级联删除B类,即在设置的那一端进行删除时,另一端才会级联删除。对应EntityManager的remove方法。 CascadeType.REFRESH:级联刷新:获取A对象时也重新获取最新的B对象。对EntityManager的refresh(object)方法。即会重新查询数据库里的最新数据(用的比较少) CascadeType.DETACH:级联分离。 CascadeType.ALL:级联所有操作。
@OneToMany(mappedBy = "boss", cascade = CascadeType.PERSIST) private List<Staff> staffList;
@OneToMany(mappedBy = "boss", cascade = CascadeType.REMOVE) private List<Staff> staffList;
package cn.netkiller.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.persistence.*;
import lombok.Data;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
@Entity
@Table
@Data
@DynamicUpdate
@DynamicInsert
@Comment("客户信息表")
public class Consumer implements Serializable {
@Serial
public static final long serialVersionUID = -1L;
@Id
// @GeneratedValue(strategy = GenerationType.IDENTITY)
// @Column(name = "id", unique = true, nullable = false, insertable = false, updatable = false, columnDefinition = "int unsigned")
@Comment("唯一ID")
// @Column(name = "id", nullable = false, columnDefinition = "int unsigned")
private Integer id;
// CascadeType.MERGE 集联更新,会更新外键表数据,覆盖
@OneToOne(cascade = CascadeType.MERGE, optional = false)
@MapsId
@JoinColumn(name = "id", nullable = false, insertable = true, updatable = false, columnDefinition = "int unsigned", foreignKey = @ForeignKey(name = "device_id"))
@JsonIgnore
private Device device;
@Comment("姓名")
@Column(length = 8)
private String name;
@Comment("昵称")
@Column(length = 16)
private String nickname;
@Comment("头像")
private String avatar;
@Comment("性别")
private Boolean gender;
@Comment("年龄")
private Integer age;
@Comment("生日")
@JsonFormat(pattern = "yyyy-MM-dd")
@Temporal(TemporalType.DATE)
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birthday;
@Comment("地址")
private String address;
@Comment("电话")
@Column(length = 15)
private String mobile;
@Column(insertable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
@Comment("创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
// @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date ctime;
@Column(nullable = true, insertable = false, updatable = false, columnDefinition = "TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP")
@Comment("修改时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
// @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date mtime;
public Consumer() {
}
}
package cn.netkiller.domain;
import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.persistence.*;
import lombok.Data;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
@Entity
@Table(uniqueConstraints = {@UniqueConstraint(columnNames = {"name", "business_id"})}
// indexes = {
// @Index(name = "key_device_unique", columnList = "name"),
// @Index(name = "key_device_unique", columnList = "business_id")
//}
)
@DynamicUpdate
@DynamicInsert
@Data
//@Builder
@Comment("设备表")
public class Device implements Serializable {
@Serial
public static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", unique = true, nullable = false, insertable = false, updatable = false, columnDefinition = "int unsigned")
@Comment("主键")
private Integer id;
@Column(nullable = false, length = 32)
@Comment("设备名称")
private String name;
@Column(unique = true, nullable = false, insertable = true, updatable = false, length = 32)
@Comment("序列号")
private String sn;
@Comment("型号")
@Column(length = 16)
private String model;
@Comment("固件版本")
@Column(length = 16)
private String fireware;
@Comment("软件版本")
@Column(length = 16)
private String version;
@Column(columnDefinition = "int unsigned")
@Comment("存储容量")
private Integer capacity = null;
@Column(columnDefinition = "int unsigned")
@Comment("可用容量")
private Integer available;
@Column(columnDefinition = "int unsigned")
@Comment("内存容量")
private Integer memory;
@Comment("移动网络提供商")
@Column(columnDefinition = "enum('中国移动','中国电信','中国联通','其他') DEFAULT NULL")
private String provider;
@Comment("IMEI")
@Column(length = 15)
private String imei;
@Comment("MEID")
@Column(length = 15)
private String meid;
@Comment("ICCID")
@Column(length = 20)
private String iccid;
@Comment("wlan 无线 mac 地址")
@Column(length = 17)
private String wlan;
@Column(length = 17)
@Comment("蓝牙 mac 地址")
private String bluetooth;
@Comment("品牌")
private String brand;
@Comment("CPU")
private String cpu;
@Comment("设备驱动")
private String device;
@Comment("显示屏")
private String display;
@Comment("设备标识")
private String fingerprint;
@Comment("硬件")
private String hardware;
@Comment("制造商")
private String manufacturer;
@Comment("产品")
private String product;
@Column(columnDefinition = "enum('Y','N') DEFAULT 'N'")
@Comment("设备状态,正常=Y,其他=N")
private String status;
@Comment("设备状态原因")
@Column(columnDefinition = "enum('未激活','激活','充值','正常','禁用','冻结') DEFAULT '正常'")
private String reason;
@Comment("设备状态描述")
private String description;
@CreatedDate
@Column(nullable = true, insertable = true, updatable = true)
@Temporal(TemporalType.TIMESTAMP)
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Comment("访问时间")
private Date atime;
@ManyToOne
@JoinColumn(name = "business_id")
private Business business;
@Column(insertable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
// @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Comment("创建时间")
private Date ctime;
@Column(nullable = true, insertable = false, updatable = false, columnDefinition = "TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP")
// @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Comment("修改时间")
private Date mtime;
public Device() {
}
}
@Transactional
public Optional<Consumer> update(String deviceName, Consumer consumer) {
Device device = new Device();
device.setId(consumer.getId());
device.setName(deviceName);
consumer.setDevice(device);
log.debug(consumer.toString());
consumer = consumerRepository.save(consumer);
return Optional.ofNullable(consumer);
}
向 Consumer 表中增加数据,Device 表受到影响,会修改里面的数据。这就是 CascadeType.MERGE 作用,如果不想影响 Device 数据,改为 CascadeType.PERSIST
@OneToOne(cascade = CascadeType.MERGE, optional = false)
@OnDelete(action = OnDeleteAction.CASCADE)
package cn.netkiller.domain;
import jakarta.persistence.*;
import lombok.Data;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
@Entity
@Table
@DynamicUpdate
@Data
@Comment("文生图心里分析")
public class PicturePsychoanalysis implements Serializable {
@Serial
public static final long serialVersionUID = 1L;
@Id
@OneToOne()
@JoinColumn(name = "id", foreignKey = @ForeignKey(name = "picture_id"))
@OnDelete(action = OnDeleteAction.CASCADE)
private Picture picture;
// @Column(unique = true, nullable = false, insertable = true, updatable = false)
// @Comment("会话")
// private String session;
@Comment("负向情绪|中性情绪|正向情绪")
private String sentiment;
@Comment("感谢|愉快|抱怨|愤怒|喜爱|厌恶|恐惧|悲伤")
private String emotion;
@Lob
@Basic(fetch = FetchType.LAZY)
@Column(nullable = true, columnDefinition = "text")
@Comment("建议回复话术")
private String replies;
@Lob
@Basic(fetch = FetchType.LAZY)
@Column(nullable = true, columnDefinition = "text")
@Comment("心里分析")
private String analysis;
@Column(insertable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
@Comment("创建时间")
private Date ctime;
@Column(nullable = true, insertable = false, updatable = false, columnDefinition = "TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP")
@Comment("修改时间")
private Date mtime;
}
CREATE TABLE `picture_psychoanalysis` ( `analysis` text COMMENT '心里分析', `ctime` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `emotion` varchar(255) DEFAULT NULL COMMENT '感谢|愉快|抱怨|愤怒|喜爱|厌恶|恐惧|悲伤', `mtime` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', `replies` text COMMENT '建议回复话术', `sentiment` varchar(255) DEFAULT NULL COMMENT '负向情绪|中性情绪|正向情绪', `id` bigint unsigned NOT NULL, PRIMARY KEY (`id`), CONSTRAINT `picture_id` FOREIGN KEY (`id`) REFERENCES `picture` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='文生图心里分析'
@JoinTable(name = "table")
@OneToMany(cascade = CascadeType.ALL) @JoinTable private List<UserProfile> userProfile;
@JoinTable(name = "cust_user",
joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id")
)
@JoinTable(name = "cust_user",
inverseJoinColumns = @JoinColumn(name = "user_ext_id", referencedColumnName = "id")
)
@JoinTable(name = "cust_user",
joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "user_ext_id", referencedColumnName = "id"),
uniqueConstraints = {
@UniqueConstraint(name = "unique_user_id", columnNames = {"user_id"}),
@UniqueConstraint(name = "unique_user_ext_id", columnNames = {"user_ext_id"})
}
)
package cn.netkiller.domain;
import jakarta.persistence.*;
import lombok.Data;
import java.io.Serializable;
@Entity
@Table
@Data
public class Consumer implements Serializable {
public static final long serialVersionUID = 7998903421265538801L;
public String firstName;
public String lastName;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", unique = true, nullable = false, insertable = false, updatable = false, columnDefinition = "int unsigned")
public Integer id;
@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinTable(name = "consumer_has_device",
joinColumns =
{@JoinColumn(name = "consumer_id", referencedColumnName = "id")},
inverseJoinColumns =
{@JoinColumn(name = "device_id", referencedColumnName = "id")})
private Device device;
public Consumer() {
}
}
package cn.netkiller.domain;
import jakarta.persistence.*;
import lombok.Data;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.DynamicUpdate;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
@Entity
@Table
@DynamicUpdate
@Data
@Comment("设备表")
public class Device implements Serializable {
@Serial
public static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", unique = true, nullable = false, insertable = false, updatable = false, columnDefinition = "int unsigned")
@Comment("主键")
private Integer id;
@Comment("设备名称")
private String name;
@Comment("型号")
private String model;
@Comment("版本")
private String fireware;
@Comment("版本")
private String version;
@Column(unique = true, nullable = false, insertable = true, updatable = false)
@Comment("序列号")
private String sn;
@Comment("ip")
private String ip;
@Comment("mac")
private String mac;
@Temporal(TemporalType.TIMESTAMP)
@Comment("最后一次登陆时间")
private Date lastTime;
@Column(columnDefinition = "enum('Y','N') DEFAULT 'N'")
@Comment("设备状态")
private boolean status;
@Column(insertable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
@Comment("创建时间")
private Date ctime;
@Column(nullable = true, insertable = false, updatable = false, columnDefinition = "TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP")
@Comment("修改时间")
private Date mtime;
}
CREATE TABLE `consumer` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`first_name` varchar(255) DEFAULT NULL,
`last_name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
CREATE TABLE `device` (
`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`ctime` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`fireware` varchar(255) DEFAULT NULL COMMENT '版本',
`ip` varchar(255) DEFAULT NULL COMMENT 'ip',
`last_time` datetime(6) DEFAULT NULL COMMENT '最后一次登陆时间',
`mac` varchar(255) DEFAULT NULL COMMENT 'mac',
`model` varchar(255) DEFAULT NULL COMMENT '型号',
`mtime` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
`name` varchar(255) DEFAULT NULL COMMENT '设备名称',
`sn` varchar(255) NOT NULL COMMENT '序列号',
`status` enum('Y','N') DEFAULT 'N' COMMENT '设备状态',
`version` varchar(255) DEFAULT NULL COMMENT '版本',
PRIMARY KEY (`id`),
UNIQUE KEY `UK_bg7pgyvfwv0q65tmquumxff3d` (`sn`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='设备表'
CREATE TABLE `consumer_has_device` (
`device_id` int unsigned DEFAULT NULL,
`consumer_id` int unsigned NOT NULL,
PRIMARY KEY (`consumer_id`),
UNIQUE KEY `UK_ibck20j1s6ch97lncg99uvpgh` (`device_id`),
CONSTRAINT `FKcottusf6sx3bnouahp29vjdwk` FOREIGN KEY (`device_id`) REFERENCES `device` (`id`),
CONSTRAINT `FKq7u4eyw8pmfkwg4yymjljx8ra` FOREIGN KEY (`consumer_id`) REFERENCES `consumer` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
// JPA 默认根据 Student 的 ID 主键对 studentList 集合数据进行递增排序
@OneToMany(cascade = CascadeType.ALL)
@OrderBy
private List<Student> studentList;
// 手动指定 id 字段的排序方式,ASC 递增排序,DESC 递减排序
@OneToMany(cascade = CascadeType.ALL)
@OrderBy("id desc")
private List<Student> studentList;
// 手动指定按照 salary 属性进行递减排序
@OneToMany(cascade = CascadeType.ALL)
@OrderBy("salary desc")
private List<Student> studentList;
// 手动指定按照多个属性进行排序
// 下面将根据 sex 和 salay 进行递增排序
@OneToMany(cascade = CascadeType.ALL)
@OrderBy("sex,salary")
private List<Student> studentList;
// 下面将根据 sex 递增排序,salary 递增排序
@OneToMany(cascade = CascadeType.ALL)
@OrderBy("sex asc,salary asc")
private List<Student> studentList;
// 下面将根据 sex 递增排序,salary 递减排序
@OneToMany(cascade = CascadeType.ALL)
@OrderBy("sex asc,salary desc")
private List<Student> studentList;
当使用 @OneToMany 与 @ManyToOne 相互引用时,你会发现产生了循环调用,此时可以使用 @JsonIgnoreProperties 避免出现循环,此时加入 @Transient 或 @JsonIgnore 注解可以解决,但要该字段就没有外键数据了。
@Entity
public class Subarea {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@OneToMany
@JsonIgnoreProperties(value = {"subarea"})
@JoinColumn(name = "subarea_id")
private List<SubareaSet> subareaSetList;
}
@Entity
public class SubareaSet {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@ManyToOne
@JsonIgnoreProperties(value = {"subareaSetList"})
private Subarea subarea;
}
optional = true 允许外键为空
@Comment("合作商")
@ManyToOne(fetch = FetchType.LAZY, optional = true)
@JoinColumn(name = "business_id", updatable = false)
@JsonIgnore
private Business business;
@Comment("合作商")
@ManyToOne(fetch = FetchType.LAZY, optional = true)
@JoinColumn(name = "business_id", updatable = false)
@JsonIgnore
private Business business;
package cn.netkiller.domain.story;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.persistence.*;
import lombok.Data;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
@Entity
@Table
@DynamicUpdate
@DynamicInsert
@Data
@Comment("图片表")
//@SecondaryTable(name = "picture_psychoanalysis",
// pkJoinColumns = @PrimaryKeyJoinColumn(name = "id")
//)
public class Picture implements Serializable {
@Serial
public static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", unique = true, nullable = false, insertable = false, updatable = false, columnDefinition = "bigint unsigned")
@Comment("主键")
private Long id;
@Comment("设备")
private String device;
@Column(unique = true, nullable = false, insertable = true, updatable = false, length = 36)
@Comment("会话")
private String session;
@Comment("提示词")
private String prompt;
@Comment("英文提示词")
@Column(length = 1024)
private String translate;
@Column(nullable = true)
@Comment("缩图")
private String thumbnail;
@Column(nullable = true)
@Comment("原图")
private String image;
@Column(nullable = true)
@Comment("故事音频")
private String audio;
@Lob
@Basic(fetch = FetchType.LAZY)
@Column(nullable = true, columnDefinition = "text")
@Comment("故事")
private String story;
@Lob
@Basic(fetch = FetchType.LAZY)
@Column(nullable = true, columnDefinition = "text")
@Comment("拼音")
private String pinyin;
@Lob
@Basic(fetch = FetchType.LAZY)
@Column(nullable = true, columnDefinition = "text")
@Comment("英文")
private String english;
@Comment("共享")
private boolean share;
@Column(columnDefinition = "int unsigned NOT NULL DEFAULT '0'")
@Comment("点赞数")
private Integer likes;
@Column(columnDefinition = "int unsigned NOT NULL DEFAULT '0'")
@Comment("收藏数")
private Integer favorites;
@Column(columnDefinition = "int unsigned NOT NULL DEFAULT '0'")
@Comment("转发数")
private Integer forward;
@Comment("人工审核,NULL 未审核,true 通过,false 未通过")
private Boolean audit;
@ManyToOne(fetch = FetchType.LAZY, optional = true)
@JsonIgnore
@JoinColumn(nullable = true)
private PictureGroup pictureGroup;
@Column(insertable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Comment("创建时间")
private Date ctime;
@Column(nullable = true, insertable = false, updatable = false, columnDefinition = "TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Comment("修改时间")
private Date mtime;
}
package cn.netkiller.domain.story;
import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.persistence.*;
import lombok.Data;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
@Entity
@Table
@DynamicUpdate
@DynamicInsert
@Data
@Comment("图片组")
public class PictureGroup implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", unique = true, nullable = false, insertable = false, updatable = false, columnDefinition = "int unsigned")
@Comment("主键")
private Integer id;
@Comment("组名")
@Column(unique = true, length = 50)
private String name;
@OneToMany(mappedBy = "pictureGroup", fetch = FetchType.EAGER)
private List<Picture> picture;
@Column(insertable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Comment("创建时间")
private Date ctime;
@Column(nullable = true, insertable = false, updatable = false, columnDefinition = "TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Comment("修改时间")
private Date mtime;
}
CREATE TABLE `picture` ( `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', `ctime` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `device` varchar(255) DEFAULT NULL COMMENT '设备', `favorites` int unsigned NOT NULL DEFAULT '0' COMMENT '收藏', `forward` int unsigned NOT NULL DEFAULT '0' COMMENT '转发', `image` varchar(255) DEFAULT NULL COMMENT '原图', `likes` int unsigned NOT NULL DEFAULT '0' COMMENT '点赞', `model` varchar(255) DEFAULT NULL COMMENT '型号', `mtime` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', `prompt` varchar(255) DEFAULT NULL COMMENT '提示词', `session` varchar(36) NOT NULL COMMENT '会话', `share` bit(1) NOT NULL COMMENT '共享\r\n0、未共享\r\n1、已共享', `story` text COMMENT '故事', `thumbnail` varchar(255) DEFAULT NULL COMMENT '缩图', `audio` varchar(255) DEFAULT NULL COMMENT '故事音频', `translate` varchar(1024) DEFAULT NULL COMMENT '英文提示词', `pinyin` text COMMENT '拼音', `english` text COMMENT '英文', `audit` bit(1) DEFAULT NULL COMMENT '人工审核\r\n0、审核未通过\r\n1、审核通过\r\n', `picture_group_id` int unsigned DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `UK_6cgmptiqeq2nusk40x5io55oh` (`session`), KEY `index_Is_Charging_Id` (`is_charging`,`device`,`charging_time`) USING BTREE, KEY `FK8qckqvv3cl83c9ant5wx1f6eo` (`picture_group_id`), CONSTRAINT `FK8qckqvv3cl83c9ant5wx1f6eo` FOREIGN KEY (`picture_group_id`) REFERENCES `picture_group` (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=5846 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='图片表'
@ManyToOne 关系 PictureGroup 加载后会出很多数据,在网上传输比较占用带宽,我们要精简 JSON 数据,实现的方式是讲 pictureGroup 影射给 groupId
package cn.netkiller.domain.story;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.persistence.*;
import lombok.Data;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
@Entity
@Table
@DynamicUpdate
@DynamicInsert
@Data
@Comment("图片表")
public class Picture implements Serializable {
@Serial
public static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", unique = true, nullable = false, insertable = false, updatable = false, columnDefinition = "bigint unsigned")
@Comment("主键")
private Long id;
@Comment("设备")
private String device;
@Column(unique = true, nullable = false, insertable = true, updatable = false, length = 36)
@Comment("会话")
private String session;
@Comment("提示词")
private String prompt;
@Comment("英文提示词")
@Column(length = 1024)
private String translate;
@Column(nullable = true)
@Comment("缩图")
private String thumbnail;
@Column(nullable = true)
@Comment("原图")
private String image;
@Column(nullable = true)
@Comment("故事音频")
private String audio;
@Lob
@Basic(fetch = FetchType.LAZY)
@Column(nullable = true, columnDefinition = "text")
@Comment("故事")
private String story;
@Lob
@Basic(fetch = FetchType.LAZY)
@Column(nullable = true, columnDefinition = "text")
@Comment("拼音")
private String pinyin;
@Lob
@Basic(fetch = FetchType.LAZY)
@Column(nullable = true, columnDefinition = "text")
@Comment("英文")
private String english;
@Comment("共享")
private boolean share;
@Column(columnDefinition = "int unsigned NOT NULL DEFAULT '0'")
@Comment("点赞数")
private Integer likes;
@Column(columnDefinition = "int unsigned NOT NULL DEFAULT '0'")
@Comment("收藏数")
private Integer favorites;
@Column(columnDefinition = "int unsigned NOT NULL DEFAULT '0'")
@Comment("转发数")
private Integer forward;
@Comment("人工审核,NULL 未审核,true 通过,false 未通过")
private Boolean audit;
@ManyToOne(fetch = FetchType.EAGER, optional = true)
@JsonIgnore
@JoinColumn(nullable = true)
private PictureGroup pictureGroup;
@Column(insertable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Comment("创建时间")
private Date ctime;
@Column(nullable = true, insertable = false, updatable = false, columnDefinition = "TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Comment("修改时间")
private Date mtime;
@JsonProperty
private Integer groupId;
private void setGroupId(Integer groupId) {
this.groupId = groupId;
}
private Integer getGroupId() {
groupId = pictureGroup.getId();
return groupId;
}
}