想在部署的时候随应用的启动而初始化数据脚本,这不就是Spring Data Jpa
中的自动生成表结构,听起来特别简单,不就是配置Hibernate
的ddl-auto
嘛,有什么好说的,是我的都知道。当初我也是这样认为,实际操做了一把,虽然表是建立成功了,可是字段注释,字符集以及数据库引擎都不对,没想到在这些细节上翻车了。java
毕竟开翻的车还要本身扶起来,粗略写点救援过程。mysql
注:本文中使用的Spring Data JPA
版本为2.1.4.RELEASEgit
以MySQL
为例,其它数据库可自行验证:spring
import com.fasterxml.jackson.annotation.*; import org.hibernate.annotations.*; import org.springframework.data.annotation.*; import javax.persistence.*; import javax.persistence.Entity; import javax.persistence.Id; import java.math.BigDecimal; @Entity @javax.persistence.Table(name = "basic_city") @org.hibernate.annotations.Table(appliesTo = "basic_city", comment = "城市基本信息") public class CityDO { @Id @GenericGenerator(name = "idGenerator", strategy = "uuid") @GeneratedValue(generator = "idGenerator") @Column(name = "CITY_ID", length = 32) private String cityId; @Column(name = "CITY_NAME_CN", columnDefinition = "VARCHAR(255) NOT NULL COMMENT '名称(中文)'") private String cityNameCN; @Column(name = "CITY_NAME_EN", columnDefinition = "VARCHAR(255) NOT NULL COMMENT '名称(英文)'") private String cityNameEN; @Column(name = "LONGITUDE", precision = 10, scale = 7) private BigDecimal longitude; @Column(name = "LATITUDE", precision = 10, scale = 7) private BigDecimal latitude; @Column(name = "ELEVATION", precision = 5) private Integer elevation; @Column(name = "CITY_DESCRIPTION", length = 500) private String cityDescription; // 构造方法及get/set方法省略 }
用到的注解简要说明一下:sql
@javax.persistence.Table
修改默认ORM
规则,属性name
设置表名;@org.hibernate.annotations.Table
建表时的描述, 属性comment
修改表描述;@Id
主键@GenericGenerator
该注解为Hibernate
的注解,用来生成表的主键策略,属性strategy
的值在类DefaultIdentifierGeneratorFactory
中定义:数据库
uuid2
: UUIDGenerator.class
;guid
: GUIDGenerator.class
;uuid
: UUIDHexGenerator.class
;uuid.hex
: UUIDHexGenerator.class
;assigned
: Assigned.class
;identity
: IdentityGenerator.class
;select
: SelectGenerator.class
;sequence
: SequenceStyleGenerator.class
;seqhilo
: SequenceHiLoGenerator.class
;increment
: IncrementGenerator.class
;foreign
: ForeignGenerator.class
;sequence-identity
: SequenceIdentityGenerator.class
;enhanced-sequence
: SequenceStyleGenerator.class
;enhanced-table
: TableGenerator.class
;@GeneratedValue
设置主键策略,这里属性generator
指向@GenericGenerator
策略的name
,属性strategy
有四个枚举值:segmentfault
GenerationType.TABLE
使用一个额外的表来存储主键;GenerationType.SEQUENCE
使用序列的方式存储,且须要数据库底层支持;GenerationType.IDENTITY
由数据库生成,通常为主键自增等;GenerationType.AUTO
表示由程序生成,不声明则默认为该属性;@Column
修改默认的ORM
规则,属性有:app
name
设置表中字段名称,表字段和实体类属性相同,则该属性可不写;unique
设置该字段在表中是否惟一,默认false
;nullable
是否可为空,默认true
;insertable
表示insert
操做时该字段是否响应写入,默认为true
;updatable
表示update
操做时该字段是否响应修改,默认为true
;columnDefinition
是自定义字段,能够用这个属性来设置字段的注释;table
表示当映射多个表时,指定表的表中的字段,默认值为主表的表名;length
是长度,仅对varchar
类型的字段生效,默认长度为255;precision
表示一共多少位;scale
表示小数部分占precision
总位数的多少位,例子中二者共同使用来确保经纬度的精度;接下来须要设置数据引擎和字符集,网上的例子都大把的继承MySQL5InnoDBDialect
,可是这个类已通过期了,咱们这里用MySQL5Dialect
:ide
package com.jason.config; import org.hibernate.dialect.MySQL5Dialect; import org.springframework.stereotype.Component; @Component public class MySQL5TableType extends MySQL5Dialect { @Override public String getTableTypeString() { return "ENGINE=InnoDB DEFAULT CHARSET=utf8"; } }
而后在Spring Boot
的配置文件中应用上面定义的MySQL5TableType
,使用spring.jpa.properties.hibernate.dialect
配置(注意书写格式,这里使用的是yml
文件):单元测试
spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/techno?useUnicode=true&characterEncoding=utf8 username: root password: root jpa: hibernate: ddl-auto: update database-platform: org.hibernate.dialect.MySQL5InnoDBDialect properties: hibernate: dialect: com.jason.config.MySQL5TableType
jpa.hibernate.ddl-auto
使用update
,其它值及说明为:
create
: 启动服务时都会从新建立表,且无论表存不存在;create-drop
: 启动服务时都会从新建立表,且无论表存不存在,服务中止时删除全部表,无论表中是否有数据;update
: 启动服务时,自动更新表结构,但数据库表中存在的旧字段不会删除;validate
: 启动服务时验证表结构,若表结构存在差别则抛出异常;至此,Sprign Data JPA
生成表结构就完成了,当咱们创建数据库后,启动服务就能够在MySQL
中获得表结构了,应用能够经过ApplicaitonRunner
或者CommandLineRunner
接口一键部署,省去了初始化SQL
等没必要要的操做,这两个接口的简单使用能够参考个人另外一篇文章。
最后咱们再上一个例子,主要是写入默认值等,部分说明就直接以注释的形式写到代码里,还有@ColumnDefault
注解这里就不作说明,你们能够本身了解下:
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import org.hibernate.annotations.*; import org.springframework.data.jpa.repository.*; import javax.persistence.*; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.Table; import javax.persistence.Temporal; import java.util.Date; @ApiModel(value = "帐号基础信息") @Entity @Table(name = "basic_account") @org.hibernate.annotations.Table(appliesTo = "basic_account", comment = "帐号基础信息表") public class AccountDO { @ApiModelProperty(name = "accountId", value = "帐号Id", hidden = true) @Id @GenericGenerator(name = "idGenerator", strategy = "uuid") @GeneratedValue(generator = "idGenerator") @Column(name = "ACCOUNT_ID", length = 32) private String accountId; @ApiModelProperty(name = "username", value = "帐号", dataType = "String", required = true) @Column(length = 32, nullable = false) private String username; // 假设密码加密后长度为128 @ApiModelProperty(name = "password", value = "密码", dataType = "String", required = true) @Column(length = 128, nullable = false) private String password; // 新建的帐号未过时,默认值给1,这个值由数据库生成,则设置insertable为false @ApiModelProperty(name = "isAccountNonExpired", value = "帐号是否过时", hidden = true) @Column(name = "IS_ACCOUNT_EXPIRED", insertable = false, columnDefinition = "CHAR(1) NOT NULL DEFAULT '1' COMMENT '帐号 0:过时;1:未过时'") private Integer isAccountNonExpired; // 新建的帐号未锁定,默认值给1,这个值由数据库生成,则设置insertable为false @Column(name = "IS_ACCOUNT_LOCKED", insertable = false, columnDefinition = "CHAR(1) NOT NULL DEFAULT '1' COMMENT '帐号 0:锁定;1:未锁定'") @ApiModelProperty(name = "isAccountNonLocked", value = "帐号是否锁定", hidden = true) private Integer isAccountNonLocked; // 新建的帐号密码未过时,默认值给1,这个值由数据库生成,则设置insertable为false @Column(name = "IS_CREDENTIALS_EXPIRED", insertable = false, columnDefinition = "CHAR(1) NOT NULL DEFAULT '1' COMMENT '密码 0:已过时;1:未过时'") @ApiModelProperty(name = "isCredentialsNonExpired", value = "密码是否过时", hidden = true) private Integer isCredentialsNonExpired; // 新建的帐号须要激活,默认值给0,这个值由数据库生成,设置insertable为false @ApiModelProperty(name = "isEnabled", value = "帐号是否可用", hidden = true) @Column(name = "IS_ENABLE", insertable = false, columnDefinition = "CHAR(1) NOT NULL DEFAULT '0' COMMENT '帐号 0:不可用;1:可用'") private Integer isEnabled; // 新建的帐号,默认值给1,这个值由数据库生成,设置insertable为false @ApiModelProperty(name = "isDelete", value = "帐号是否删除", hidden = true) @Column(name = "IS_DELETE", insertable = false, columnDefinition = "CHAR(1) NOT NULL DEFAULT '1' COMMENT '帐号 0:已删除;1:未删除'") private Integer isDelete; // 新建帐号时间不能修改,设置updatable为false,但此处不能设置insertable = false // @Temporal(TemporalType.TIMESTAMP) 因为表字段类型为TIMESTAMP,因此将Date转换为TIMESTAMP @ApiModelProperty(name = "createTimestamp", value = "建立时间") @Column(name = "CREATE_TIMESTAMP", nullable = false, updatable = false) @Temporal(TemporalType.TIMESTAMP) @CreationTimestamp private Date createTimestamp; public AccountDO(String username,String password) { this.username = username; this.password = password; } // 其余构造方法及get/set方法省略 }
注:@ApiModel
以及@ApiModelProperty
为swagger
注解。
咱们注册帐号的单元测试就能够直接写成下面这样,仅填写帐号和密码,其余值则由数据库生成:
@Test public void saveAccount() throws Exception { accountService.saveAccount(new AccountDO("123456", "654321")); }
原创不易,感谢支持。