摘要:想在部署的時(shí)候隨應(yīng)用的啟動(dòng)而初始化數(shù)據(jù)腳本,這不就是中的自動(dòng)生成表結(jié)構(gòu),聽(tīng)起來(lái)特別簡(jiǎn)單,不就是配置的嘛,有什么好說(shuō)的,是個(gè)人都知道。
想在部署的時(shí)候隨應(yīng)用的啟動(dòng)而初始化數(shù)據(jù)腳本,這不就是Spring Data Jpa中的自動(dòng)生成表結(jié)構(gòu),聽(tīng)起來(lái)特別簡(jiǎn)單,不就是配置Hibernate的ddl-auto嘛,有什么好說(shuō)的,是個(gè)人都知道。當(dāng)初我也是這樣認(rèn)為,實(shí)際操作了一把,雖然表是創(chuàng)建成功了,但是字段注釋?zhuān)址约皵?shù)據(jù)庫(kù)引擎都不對(duì),沒(méi)想到在這些細(xì)節(jié)上翻車(chē)了。
畢竟開(kāi)翻的車(chē)還要自己扶起來(lái),粗略寫(xiě)點(diǎn)救援過(guò)程。
注:本文中使用的Spring Data JPA版本為2.1.4.RELEASE
以MySQL為例,其它數(shù)據(jù)庫(kù)可自行驗(yàn)證:
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 "名稱(chēng)(中文)"") private String cityNameCN; @Column(name = "CITY_NAME_EN", columnDefinition = "VARCHAR(255) NOT NULL COMMENT "名稱(chēng)(英文)"") 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; // 構(gòu)造方法及get/set方法省略 }
用到的注解簡(jiǎn)要說(shuō)明一下:
@javax.persistence.Table 修改默認(rèn)ORM規(guī)則,屬性name設(shè)置表名;
@org.hibernate.annotations.Table 建表時(shí)的描述, 屬性comment修改表描述;
@Id 主鍵
@GenericGenerator 該注解為Hibernate的注解,用來(lái)生成表的主鍵策略,屬性strategy的值在類(lèi)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 設(shè)置主鍵策略,這里屬性generator指向@GenericGenerator策略的name,屬性strategy有四個(gè)枚舉值:
GenerationType.TABLE 使用一個(gè)額外的表來(lái)存儲(chǔ)主鍵;
GenerationType.SEQUENCE 使用序列的方式存儲(chǔ),且需要數(shù)據(jù)庫(kù)底層支持;
GenerationType.IDENTITY 由數(shù)據(jù)庫(kù)生成,一般為主鍵自增等;
GenerationType.AUTO 表示由程序生成,不聲明則默認(rèn)為該屬性;
@Column 修改默認(rèn)的ORM規(guī)則,屬性有:
name設(shè)置表中字段名稱(chēng),表字段和實(shí)體類(lèi)屬性相同,則該屬性可不寫(xiě);
unique設(shè)置該字段在表中是否唯一,默認(rèn)false;
nullable是否可為空,默認(rèn)true;
insertable表示insert操作時(shí)該字段是否響應(yīng)寫(xiě)入,默認(rèn)為true;
updatable表示update操作時(shí)該字段是否響應(yīng)修改,默認(rèn)為true;
columnDefinition是自定義字段,可以用這個(gè)屬性來(lái)設(shè)置字段的注釋?zhuān)?/p>
table表示當(dāng)映射多個(gè)表時(shí),指定表的表中的字段,默認(rèn)值為主表的表名;
length是長(zhǎng)度,僅對(duì)varchar類(lèi)型的字段生效,默認(rèn)長(zhǎng)度為255;
precision表示一共多少位;
scale表示小數(shù)部分占precision總位數(shù)的多少位,例子中兩者共同使用來(lái)確保經(jīng)緯度的精度;
接下來(lái)需要設(shè)置數(shù)據(jù)引擎和字符集,網(wǎng)上的例子都大把的繼承MySQL5InnoDBDialect,但是這個(gè)類(lèi)已經(jīng)過(guò)期了,我們這里用MySQL5Dialect:
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的配置文件中應(yīng)用上面定義的MySQL5TableType,使用spring.jpa.properties.hibernate.dialect配置(注意書(shū)寫(xiě)格式,這里使用的是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,其它值及說(shuō)明為:
create: 啟動(dòng)服務(wù)時(shí)都會(huì)重新創(chuàng)建表,且不管表存不存在;
create-drop: 啟動(dòng)服務(wù)時(shí)都會(huì)重新創(chuàng)建表,且不管表存不存在,服務(wù)停止時(shí)刪除所有表,不管表中是否有數(shù)據(jù);
update: 啟動(dòng)服務(wù)時(shí),自動(dòng)更新表結(jié)構(gòu),但數(shù)據(jù)庫(kù)表中存在的舊字段不會(huì)刪除;
validate: 啟動(dòng)服務(wù)時(shí)驗(yàn)證表結(jié)構(gòu),若表結(jié)構(gòu)存在差異則拋出異常;
至此,Sprign Data JPA生成表結(jié)構(gòu)就完成了,當(dāng)我們建立數(shù)據(jù)庫(kù)后,啟動(dòng)服務(wù)就可以在MySQL中得到表結(jié)構(gòu)了,應(yīng)用可以通過(guò)ApplicaitonRunner或者CommandLineRunner接口一鍵部署,省去了初始化SQL等不必要的操作,這兩個(gè)接口的簡(jiǎn)單使用可以參考我的另外一篇文章。
最后我們?cè)偕弦粋€(gè)例子,主要是寫(xiě)入默認(rèn)值等,部分說(shuō)明就直接以注釋的形式寫(xiě)到代碼里,還有@ColumnDefault注解這里就不做說(shuō)明,大家可以自己了解下:
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 = "賬號(hào)基礎(chǔ)信息") @Entity @Table(name = "basic_account") @org.hibernate.annotations.Table(appliesTo = "basic_account", comment = "賬號(hào)基礎(chǔ)信息表") public class AccountDO { @ApiModelProperty(name = "accountId", value = "賬號(hào)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 = "賬號(hào)", dataType = "String", required = true) @Column(length = 32, nullable = false) private String username; // 假設(shè)密碼加密后長(zhǎng)度為128 @ApiModelProperty(name = "password", value = "密碼", dataType = "String", required = true) @Column(length = 128, nullable = false) private String password; // 新建的賬號(hào)未過(guò)期,默認(rèn)值給1,這個(gè)值由數(shù)據(jù)庫(kù)生成,則設(shè)置insertable為false @ApiModelProperty(name = "isAccountNonExpired", value = "賬號(hào)是否過(guò)期", hidden = true) @Column(name = "IS_ACCOUNT_EXPIRED", insertable = false, columnDefinition = "CHAR(1) NOT NULL DEFAULT "1" COMMENT "賬號(hào) 0:過(guò)期;1:未過(guò)期"") private Integer isAccountNonExpired; // 新建的賬號(hào)未鎖定,默認(rèn)值給1,這個(gè)值由數(shù)據(jù)庫(kù)生成,則設(shè)置insertable為false @Column(name = "IS_ACCOUNT_LOCKED", insertable = false, columnDefinition = "CHAR(1) NOT NULL DEFAULT "1" COMMENT "賬號(hào) 0:鎖定;1:未鎖定"") @ApiModelProperty(name = "isAccountNonLocked", value = "賬號(hào)是否鎖定", hidden = true) private Integer isAccountNonLocked; // 新建的賬號(hào)密碼未過(guò)期,默認(rèn)值給1,這個(gè)值由數(shù)據(jù)庫(kù)生成,則設(shè)置insertable為false @Column(name = "IS_CREDENTIALS_EXPIRED", insertable = false, columnDefinition = "CHAR(1) NOT NULL DEFAULT "1" COMMENT "密碼 0:已過(guò)期;1:未過(guò)期"") @ApiModelProperty(name = "isCredentialsNonExpired", value = "密碼是否過(guò)期", hidden = true) private Integer isCredentialsNonExpired; // 新建的賬號(hào)需要激活,默認(rèn)值給0,這個(gè)值由數(shù)據(jù)庫(kù)生成,設(shè)置insertable為false @ApiModelProperty(name = "isEnabled", value = "賬號(hào)是否可用", hidden = true) @Column(name = "IS_ENABLE", insertable = false, columnDefinition = "CHAR(1) NOT NULL DEFAULT "0" COMMENT "賬號(hào) 0:不可用;1:可用"") private Integer isEnabled; // 新建的賬號(hào),默認(rèn)值給1,這個(gè)值由數(shù)據(jù)庫(kù)生成,設(shè)置insertable為false @ApiModelProperty(name = "isDelete", value = "賬號(hào)是否刪除", hidden = true) @Column(name = "IS_DELETE", insertable = false, columnDefinition = "CHAR(1) NOT NULL DEFAULT "1" COMMENT "賬號(hào) 0:已刪除;1:未刪除"") private Integer isDelete; // 新建賬號(hào)時(shí)間不能修改,設(shè)置updatable為false,但此處不能設(shè)置insertable = false // @Temporal(TemporalType.TIMESTAMP) 由于表字段類(lèi)型為T(mén)IMESTAMP,所以將Date轉(zhuǎn)換為T(mén)IMESTAMP @ApiModelProperty(name = "createTimestamp", value = "創(chuàng)建時(shí)間") @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; } // 其他構(gòu)造方法及get/set方法省略 }
注:@ApiModel以及@ApiModelProperty為swagger注解。
我們注冊(cè)賬號(hào)的單元測(cè)試就可以直接寫(xiě)成下面這樣,僅填寫(xiě)賬號(hào)和密碼,其他值則由數(shù)據(jù)庫(kù)生成:
@Test public void saveAccount() throws Exception { accountService.saveAccount(new AccountDO("123456", "654321")); }
原創(chuàng)不易,感謝支持。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/74340.html
摘要:的配置后在其他低版本的中也有使用這種配置的,具體根據(jù)版本而定。等注解是的相關(guān)知識(shí),后面的文章將詳細(xì)講述。 ??在我們的實(shí)際開(kāi)發(fā)的過(guò)程中,無(wú)論多復(fù)雜的業(yè)務(wù)邏輯到達(dá)持久層都回歸到了增刪改查的基本操作,可能會(huì)存在關(guān)聯(lián)多張表的復(fù)雜sql,但是對(duì)于單表的增刪改查也是不可避免的,大多數(shù)開(kāi)發(fā)人員對(duì)于這個(gè)簡(jiǎn)單而繁瑣的操作都比較煩惱。 ??為了解決這種大量枯燥的簡(jiǎn)單數(shù)據(jù)庫(kù)操作,大致的解決該問(wèn)題的有三種方...
摘要:文章系列從零入門(mén)系列之從零入門(mén)系列之程序結(jié)構(gòu)設(shè)計(jì)說(shuō)明前言本篇文章開(kāi)始代碼實(shí)踐,系統(tǒng)設(shè)計(jì)從底向上展開(kāi),因此本篇先介紹如何實(shí)現(xiàn)數(shù)據(jù)庫(kù)表實(shí)體類(lèi)的設(shè)計(jì)實(shí)現(xiàn)。主鍵由數(shù)據(jù)庫(kù)自動(dòng)生成主要是自動(dòng)增長(zhǎng)型主鍵由程序控制。 文章系列 【從零入門(mén)系列-0】Sprint Boot 之 Hello World 【從零入門(mén)系列-1】Sprint Boot 之 程序結(jié)構(gòu)設(shè)計(jì)說(shuō)明 前言 本篇文章開(kāi)始代碼實(shí)踐,系統(tǒng)...
摘要:最常用的屬性,第一次加載時(shí)根據(jù)類(lèi)會(huì)自動(dòng)建立起表的結(jié)構(gòu)前提是先建立好數(shù)據(jù)庫(kù),以后加載時(shí)根據(jù)類(lèi)自動(dòng)更新表結(jié)構(gòu),即使表結(jié)構(gòu)改變了但表中的行仍然存在不會(huì)刪除以前的行。 添加依賴(lài) 新建項(xiàng)目選擇web,JPA,MySQL三個(gè)依賴(lài) showImg(https://segmentfault.com/img/bV2gNo?w=1684&h=1172); 對(duì)于已存在的項(xiàng)目可以在bulid.gradle加入...
摘要:忽略該字段的映射省略創(chuàng)建數(shù)據(jù)訪(fǎng)問(wèn)層接口,需要繼承,第一個(gè)泛型參數(shù)是實(shí)體對(duì)象的名稱(chēng),第二個(gè)是主鍵類(lèi)型。 SpringBoot 是為了簡(jiǎn)化 Spring 應(yīng)用的創(chuàng)建、運(yùn)行、調(diào)試、部署等一系列問(wèn)題而誕生的產(chǎn)物,自動(dòng)裝配的特性讓我們可以更好的關(guān)注業(yè)務(wù)本身而不是外部的XML配置,我們只需遵循規(guī)范,引入相關(guān)的依賴(lài)就可以輕易的搭建出一個(gè) WEB 工程 上一篇介紹了Spring JdbcTempl...
摘要:教程簡(jiǎn)介本項(xiàng)目?jī)?nèi)容為教程樣例。目的是通過(guò)學(xué)習(xí)本系列教程,讀者可以從到掌握的知識(shí),并且可以運(yùn)用到項(xiàng)目中。本章將進(jìn)一步講解,結(jié)合完成數(shù)據(jù)層訪(fǎng)問(wèn)。創(chuàng)建控制器在下面創(chuàng)建控制器用于測(cè)試訪(fǎng)問(wèn)程序運(yùn)行和調(diào)試在類(lèi)中,啟動(dòng)程序。 教程簡(jiǎn)介 本項(xiàng)目?jī)?nèi)容為Spring Boot教程樣例。目的是通過(guò)學(xué)習(xí)本系列教程,讀者可以從0到1掌握spring boot的知識(shí),并且可以運(yùn)用到項(xiàng)目中。如您覺(jué)得該項(xiàng)目對(duì)您有用,...
閱讀 1447·2021-11-22 15:11
閱讀 2862·2019-08-30 14:16
閱讀 2782·2019-08-29 15:21
閱讀 2935·2019-08-29 15:11
閱讀 2477·2019-08-29 13:19
閱讀 3010·2019-08-29 12:25
閱讀 443·2019-08-29 12:21
閱讀 2854·2019-08-29 11:03