Spring Data JPA 之后数据表可以自己生成,如果业务完善的话,完全不需要手动去修改数据表结构。
接下来以学生表为例子
package com.zuiuxi.plan.entity;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.DynamicUpdate;
import lombok.Data;
/**
*@author lv-gui
*@date 2021-09-26 11:12
*@description
**/
@Data
@Entity
@DynamicUpdate
@Table(name = "student")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@Column(name = "age")
private Integer age;
@Column(name = "birth")
private Date birth;
}
启动控制台输入student表创建的语句
Hibernate: create table student (id bigint not null auto_increment, age integer, birth datetime(6), name varchar(255), primary key (id)) engine=InnoDB
默认id为20位,age是Integer 11位,birth 默认到毫秒, name设置为varchar(255)
为了验证生成的表结构,application.properties中设置spring.jpa.hibernate.ddl-auto为true,这样每次数据表会自动删除重新创建。
#datasource
spirng.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=daasan7ujm^YHN
#jpa
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
注解详解
@Entity
注解表名这是一个实体类,必须。
@Table
实体映射到数据库中的表名,没有的话,按照默认的命名。必须,我们去掉这个属性再试一下
Hibernate: drop table if exists student
Hibernate: create table student (id bigint not null auto_increment, age integer, birth datetime(6), name varchar(255), primary key (id)) engine=InnoDB
控制台输出删除表student和创建student表。
我们修改类名为StudentTest再试一下
Hibernate: drop table if exists student_test
Hibernate: create table student_test (id bigint not null auto_increment, age integer, birth datetime(6), name varchar(255), primary key (id)) engine=InnoDB
默认创建了student_test,命名按照驼峰命名小写,之间用下划线分割。虽然和我们预想的是一致的,但是为了防止发生不必要的错误,这里也写上具体的名字。
如果我们写了两个一样的表名嗯,启动之后发现只创建了一张表,也不保错。
@Data
lombok中的注解,用于生成字段的setter、getter、toString()等方法,这里主要是用于生成数据表字段的setter和getter方法
@DynamicUpdate
如果数据在更新的时候,会默认去除不更新字段
Hibernate: update user set birth=? where id=?
这里只修改了birth字段,然后将数据还原,去除@DynamicUpdate注解,再去更新一下,输出结果如下,此时会把所有的字段都更新一遍
Hibernate: update user set age=?, birth=?, name=? where id=?
对于age和name字段并未更新,但如果不加@DynamicUpdate的话,它还是回去执行一遍,造成资源的浪费,这里建议加上这个属性。
@Id
表明这个属性是这个表的主键,一个表里面只有一个主键,但是可以有多个字段。
多个字段的主键是不能直接给两个字段都添加@Id的,这样会报错。
复合主键的实现
package com.zuiuxi.plan.entity;
import java.io.Serializable;
import lombok.Data;
/**
*@author lv-gui
*@date 2021-09-26 13:36
*@description
**/
@Data
public class StudentPrimaryKey implements Serializable{
private Long id;
private String name;
}
package com.zuiuxi.plan.entity;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Table;
import org.hibernate.annotations.DynamicUpdate;
import lombok.Data;
/**
*@author lv-gui
*@date 2021-09-26 11:12
*@description
**/
@Data
@Entity
@DynamicUpdate
@Table(name = "student")
@IdClass(StudentPrimaryKey.class)
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Id
@Column(name = "name")
private String name;
@Column(name = "age")
private Integer age;
@Column(name = "birth")
private Date birth;
}
create table student (id bigint not null auto_increment, name varchar(255) not null, age integer, birth datetime(6), primary key (id, name)) engine=InnoDB
使用@IdClass(StudentPrimaryKey.class) 来指定复合主键,StudentPrimaryKey类中必须实现Serializable不然启动会报错
Composite-id class must implement Serializable: com.zuiuxi.plan.entity.StudentPrimaryKey
StudentPrimaryKey只需主键字段即可,设置和对应表字段一致。
@Column
只有加上这个字段就会被生成到对应的表中,如果不写就会按照默认的命名的方式命名,和表名默认的方式一样,这里推荐所有的字段都加上
create table student (id bigint not null auto_increment, age integer, birth datetime(6), name varchar(255), remakes varchar(255), primary key (id)) engine=InnoDB
package com.zuiuxi.plan.entity;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.DynamicUpdate;
import lombok.Data;
/**
*@author lv-gui
*@date 2021-09-26 11:12
*@description
**/
@Data
@Entity
@DynamicUpdate
@Table(name = "student")
public class Student {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@Column(name = "age")
private Integer age;
@Column(name = "birth")
private Date birth;
private String remakes;
}
因此,不要的属性不要写在实体中,不然会被生成在数据表中
@GeneratedValue
GeneratedValue一共有两个属性:strategy 和 generator
strategy
主键生成策略,有如下四个值
- GenerationType.TABLE
- GenerationType.SEQUENCE
- GenerationType.IDENTITY
- GenerationType.AUTO
GenerationType.IDENTITY 主键自增长,GenerationType.AUTO 默认的设置,由程序控制。
GenerationType.TABLE创建自己的表保存数据的主键增长,GenerationType.SEQUENCE会生成一个表保存自动增长的键。
最常用的还是GenerationType.IDENTITY
generator
主键生成器
@GenericGenerator 主键生成策略
static {
GENERATORS.put(“uuid”, UUIDHexGenerator.class);
GENERATORS.put(“hilo”, TableHiLoGenerator.class);
GENERATORS.put(“assigned”, Assigned.class);
GENERATORS.put(“identity”, IdentityGenerator.class);
GENERATORS.put(“select”, SelectGenerator.class);
GENERATORS.put(“sequence”, SequenceGenerator.class);
GENERATORS.put(“seqhilo”, SequenceHiLoGenerator.class);
GENERATORS.put(“increment”, IncrementGenerator.class);
GENERATORS.put(“foreign”, ForeignGenerator.class);
GENERATORS.put(“guid”, GUIDGenerator.class);
GENERATORS.put(“uuid.hex”, UUIDHexGenerator.class); //uuid.hex is deprecated
GENERATORS.put(“sequence-identity”, SequenceIdentityGenerator.class);
}
比如:uuid策略
@GeneratedValue(generator = "IdUtilGenerator")
@GenericGenerator(name = "IdUtilGenerator", strategy = "com.zuiuxi.plan.util.IdUtilGenerator")
还可以使用自定的策略,继承对应的接口即可
例如:
@GeneratedValue(generator = "IdUtilGenerator")
@GenericGenerator(name = "IdUtilGenerator", strategy = "com.ruizhi.plan.config.IdUtilGenerator")
使用hutoolId生成器。引入hutool工具
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.13</version>
</dependency>
创建对应的类:
package com.zuiuxi.plan.util;
import java.io.Serializable;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.IdentifierGenerator;
/**
*@author lv-gui
*@date 2021-09-26 15:55
*@description id生成器
**/
public class IdUtilGenerator implements IdentifierGenerator {
@Override
public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
return cn.hutool.core.util.IdUtil.getSnowflake(1, 1).nextId();
}
}
调试一下
package com.zuiuxi.plan.entity;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.serializer.ToStringSerializer;
import lombok.Data;
/**
*@author lv.gui
*@date 创建时间:2021年9月21日 下午11:01:54
*@description
*/
@Data
@Entity
@Table(name = "user")
public class User{
@Id
@Column(name = "id")
@JSONField(serializeUsing = ToStringSerializer.class)
@GeneratedValue(generator = "IdUtilGenerator")
@GenericGenerator(name = "IdUtilGenerator", strategy = "com.zuiuxi.plan.util.IdUtilGenerator")
private Long id;
@Column(name = "name")
private String name;
@Column(name = "age")
private Integer age;
@Column(name = "birth")
private Date birth;
}
然后我们添加两条数据