原標(biāo)題:Spring認(rèn)證|Spring Data JDBC參考文檔二 (內(nèi)容來(lái)源:Spring中國(guó)教育管理中心) class Person { private final @Id Long id; private final String firstname, lastname; private final LocalDate birthday; private final int age; private String comment; private @AccessType(Type.PROPERTY) String remarks; static Person of(String firstname, String lastname, LocalDate birthday) { return new Person(null, firstname, lastname, birthday, Period.between(birthday, LocalDate.now()).getYears()); } Person(Long id, String firstname, String lastname, LocalDate birthday, int age) { this.id = id; this.firstname = firstname; this.lastname = lastname; this.birthday = birthday; this.age = age; } Person withId(Long id) { return new Person(id, this.firstname, this.lastname, this.birthday, this.age); } void setRemarks(String remarks) { this.remarks = remarks; } } identifier 屬性是最終的,,但null在構(gòu)造函數(shù)中設(shè)置為,。該類公開了一個(gè)withId(…)用于設(shè)置標(biāo)識(shí)符的方法,例如,,當(dāng)一個(gè)實(shí)例插入到數(shù)據(jù)存儲(chǔ)中并生成一個(gè)標(biāo)識(shí)符時(shí),。Person創(chuàng)建新實(shí)例時(shí),原始實(shí)例保持不變,。相同的模式通常應(yīng)用于由存儲(chǔ)管理但可能必須為持久性操作更改的其他屬性,。wither 方法是可選的,因?yàn)槌志眯詷?gòu)造函數(shù)(參見 6)實(shí)際上是一個(gè)復(fù)制構(gòu)造函數(shù),,并且設(shè)置該屬性將被轉(zhuǎn)換為創(chuàng)建一個(gè)應(yīng)用新標(biāo)識(shí)符值的新實(shí)例,。 的firstname和lastname特性是通過(guò)吸氣劑可能暴露普通不可變屬性。 該age屬性是不可變的,,但源自該birthday屬性,。使用所示設(shè)計(jì),數(shù)據(jù)庫(kù)值將勝過(guò)默認(rèn)值,,因?yàn)?Spring Data 使用唯一聲明的構(gòu)造函數(shù),。即使意圖是計(jì)算應(yīng)該是首選,重要的是此構(gòu)造函數(shù)也將age作為參數(shù)(可能會(huì)忽略它),否則屬性填充步驟將嘗試設(shè)置年齡字段并由于它不可變且沒(méi)有with…方法而失敗在場(chǎng),。 該comment屬性是可變的,,通過(guò)直接設(shè)置其字段來(lái)填充。 的remarks特性是可變的,,并且通過(guò)設(shè)置填充comment直接字段或通過(guò)調(diào)用用于setter方法 該類公開了一個(gè)工廠方法和一個(gè)用于創(chuàng)建對(duì)象的構(gòu)造函數(shù),。這里的核心思想是使用工廠方法而不是額外的構(gòu)造函數(shù),以避免需要通過(guò)@PersistenceConstructor. 相反,,屬性的默認(rèn)設(shè)置是在工廠方法中處理的,。 一般建議 盡量堅(jiān)持不可變對(duì)象?——不可變對(duì)象很容易創(chuàng)建,因?yàn)榫唧w化一個(gè)對(duì)象只是調(diào)用它的構(gòu)造函數(shù)的問(wèn)題,。此外,這避免了您的域?qū)ο蟊辉试S客戶端代碼操作對(duì)象狀態(tài)的 setter 方法所困擾,。如果您需要這些,,最好將它們打包保護(hù),以便它們只能由有限數(shù)量的并置類型調(diào)用,。僅構(gòu)造函數(shù)實(shí)現(xiàn)比屬性填充快 30%,。 提供一個(gè)全參數(shù)構(gòu)造函數(shù)?——即使你不能或不想將你的實(shí)體建模為不可變值,提供一個(gè)將實(shí)體的所有屬性(包括可變屬性)作為參數(shù)的構(gòu)造函數(shù)仍然是有價(jià)值的,,因?yàn)檫@允許對(duì)象映射以跳過(guò)屬性填充以獲得最佳性能,。 使用工廠方法而不是重載構(gòu)造函數(shù)來(lái)避免@PersistenceConstructor?——為了獲得最佳性能需要一個(gè)全參數(shù)構(gòu)造函數(shù),我們通常希望公開更多應(yīng)用程序用例特定的構(gòu)造函數(shù),,這些構(gòu)造函數(shù)省略自動(dòng)生成的標(biāo)識(shí)符等,。這是一種既定的模式,而不是使用靜態(tài)工廠方法來(lái)公開 all-args 構(gòu)造函數(shù)的這些變體,。 確保遵守允許使用生成的實(shí)例化器和屬性訪問(wèn)器類的約束?——? 對(duì)于要生成的標(biāo)識(shí)符,,仍然使用 final 字段與全參數(shù)持久性構(gòu)造函數(shù)(首選)或with…方法相結(jié)合?——? 使用 Lombok 避免樣板代碼?——由于持久性操作通常需要一個(gè)接受所有參數(shù)的構(gòu)造函數(shù),因此它們的聲明變成了對(duì)字段分配的樣板參數(shù)的乏味重復(fù),,而使用 Lombok 的@AllArgsConstructor. Kotlin 支持 Spring Data 調(diào)整了 Kotlin 的細(xì)節(jié)以允許對(duì)象創(chuàng)建和變異,。 Kotlin 對(duì)象創(chuàng)建 Kotlin 類支持實(shí)例化,默認(rèn)情況下所有類都是不可變的,,并且需要顯式屬性聲明來(lái)定義可變屬性,。考慮以下data類Person: data class Person(val id: String, val name: String) 上面的類編譯為具有顯式構(gòu)造函數(shù)的典型類,。我們可以通過(guò)添加另一個(gè)構(gòu)造函數(shù)來(lái)自定義這個(gè)類,,并使用注釋@PersistenceConstructor來(lái)指示構(gòu)造函數(shù)首選項(xiàng): data class Person(var id: String, val name: String) { @PersistenceConstructor constructor(id: String) : this(id, "unknown") } Kotlin 通過(guò)允許在未提供參數(shù)的情況下使用默認(rèn)值來(lái)支持參數(shù)可選性。當(dāng) Spring Data 檢測(cè)到具有參數(shù)默認(rèn)值的構(gòu)造函數(shù)時(shí),,如果數(shù)據(jù)存儲(chǔ)不提供值(或簡(jiǎn)單地返回null),,它就會(huì)使這些參數(shù)不存在,因此 Kotlin 可以應(yīng)用參數(shù)默認(rèn)值??紤]以下應(yīng)用參數(shù)默認(rèn)值的類name data class Person(var id: String, val name: String = "unknown") 每次name參數(shù)不是結(jié)果的一部分或其值為 時(shí)null,,則name默認(rèn)為unknown。 Kotlin 數(shù)據(jù)類的屬性填充 在 Kotlin 中,,默認(rèn)情況下所有類都是不可變的,,并且需要明確的屬性聲明來(lái)定義可變屬性??紤]以下data類Person: data class Person(val id: String, val name: String) 這個(gè)類實(shí)際上是不可變的,。它允許創(chuàng)建新實(shí)例,因?yàn)?Kotlin 生成copy(…)創(chuàng)建新對(duì)象實(shí)例的方法,,該方法從現(xiàn)有對(duì)象復(fù)制所有屬性值并將作為參數(shù)提供的屬性值應(yīng)用到該方法,。 9.6.2. 您的實(shí)體中支持的類型 目前支持以下類型的屬性: 所有原始類型及其裝箱類型(int、float,、Integer,、Float等) 枚舉被映射到他們的名字。 String java.util.Date, java.time.LocalDate, java.time.LocalDateTime, 和java.time.LocalTime 如果您的數(shù)據(jù)庫(kù)支持,,上述類型的數(shù)組和集合可以映射到數(shù)組類型的列,。 您的數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序接受的任何內(nèi)容。 對(duì)其他實(shí)體的引用,。它們被認(rèn)為是一對(duì)一的關(guān)系,,或嵌入類型。一對(duì)一關(guān)系實(shí)體是否具有id屬性是可選的,。被引用實(shí)體的表應(yīng)該有一個(gè)與引用實(shí)體表同名的附加列,。您可以通過(guò)實(shí)施來(lái)更改此名稱 Set被認(rèn)為是一對(duì)多的關(guān)系。被引用實(shí)體的表應(yīng)該有一個(gè)與引用實(shí)體表同名的附加列,。您可以通過(guò)實(shí)施來(lái)更改此名稱 Map被認(rèn)為是合格的一對(duì)多關(guān)系。被引用實(shí)體的表應(yīng)該有兩個(gè)額外的列:一個(gè)與外鍵的引用實(shí)體的表命名相同,,另一個(gè)具有相同的名稱和_key映射鍵的附加后綴,。您可以通過(guò)分別實(shí)現(xiàn) List映射為Map. 引用實(shí)體的處理是有限的。這是基于上述聚合根的思想,。如果您引用另一個(gè)實(shí)體,,則根據(jù)定義,,該實(shí)體是您的聚合的一部分。因此,,如果您刪除引用,,則先前引用的實(shí)體將被刪除。這也意味著參考是 1-1 或 1-n,,但不是 n-1 或 nm,。 如果您有 n-1 或 nm 引用,根據(jù)定義,,您正在處理兩個(gè)單獨(dú)的聚合,。這些之間的引用應(yīng)該被編碼為簡(jiǎn)單的id值,應(yīng)該與 Spring Data JDBC 正確映射,。 9.6.3. 自定義轉(zhuǎn)換器 對(duì)于默認(rèn)情況下不支持的類型,,可以通過(guò)繼承您的配置AbstractJdbcConfiguration并覆蓋方法來(lái)注冊(cè)自定義轉(zhuǎn)換器jdbcCustomConversions()。 @Configuration public class DataJdbcConfiguration extends AbstractJdbcConfiguration { @Override public JdbcCustomConversions jdbcCustomConversions() { return new JdbcCustomConversions(Collections.singletonList(TimestampTzToDateConverter.INSTANCE)); } @ReadingConverter enum TimestampTzToDateConverter implements Converter { INSTANCE; @Override public Date convert(TIMESTAMPTZ source) { //... } } } 的構(gòu)造函數(shù)JdbcCustomConversions接受 的列表 轉(zhuǎn)換器應(yīng)該用@ReadingConverter或進(jìn)行注釋,,@WritingConverter以控制它們僅從數(shù)據(jù)庫(kù)讀取或?qū)懭霐?shù)據(jù)庫(kù)的適用性。 TIMESTAMPTZ 示例中的數(shù)據(jù)庫(kù)特定數(shù)據(jù)類型需要轉(zhuǎn)換為更適合域模型的數(shù)據(jù)類型,。 數(shù)據(jù)庫(kù)值 值轉(zhuǎn)換用于JdbcValue豐富傳播到具有java.sql.Types類型的JDBC 操作的值。如果您需要指定特定于 JDBC 的類型而不是使用類型派生,,請(qǐng)注冊(cè)自定義寫入轉(zhuǎn)換器,。此轉(zhuǎn)換器應(yīng)將值轉(zhuǎn)換JdbcValue為具有值和實(shí)際JDBCType. 9.6.4. NamingStrategy 當(dāng)您使用CrudRepositorySpring Data JDBC 提供的標(biāo)準(zhǔn)實(shí)現(xiàn)時(shí),它們需要特定的表結(jié)構(gòu),。您可以通過(guò)NamingStrategy在應(yīng)用程序上下文中提供 a 來(lái)調(diào)整它,。 9.6.5. Custom table names 當(dāng) NamingStrategy 與您的數(shù)據(jù)庫(kù)表名稱不匹配時(shí),您可以使用@Table注釋自定義名稱,。value此注釋的元素提供自定義表名稱,。以下示例將MyEntity類映射到CUSTOM_TABLE_NAME數(shù)據(jù)庫(kù)中的表: @Table("CUSTOM_TABLE_NAME") public class MyEntity { @Id Integer id; String name; } 9.6.6. Custom column names 當(dāng) NamingStrategy 與您的數(shù)據(jù)庫(kù)列名稱不匹配時(shí),您可以使用@Column注釋自定義名稱,。value此注釋的元素提供自定義列名稱,。以下示例將類的name屬性映射MyEntity到CUSTOM_COLUMN_NAME數(shù)據(jù)庫(kù)中的列: public class MyEntity { @Id Integer id; @Column("CUSTOM_COLUMN_NAME") String name; } 該@MappedCollection 注釋可以對(duì)引用類型(一對(duì)一的關(guān)系)或集合,列表被使用,,并且圖(一個(gè)一對(duì)多關(guān)系),。 idColumn注釋的元素為引用另一個(gè)表中的 id 列的外鍵列提供自定義名稱。在下面的例子中,,MySubEntity類的對(duì)應(yīng)表有一個(gè)NAME列,,以及出于關(guān)系原因 public class MyEntity { @Id Integer id; @MappedCollection(idColumn = "CUSTOM_MY_ENTITY_ID_COLUMN_NAME") Set subEntities; } public class MySubEntity { String name; } 當(dāng)使用List和Map您必須在數(shù)據(jù)集中的位置的附加列List或?qū)嶓w的鍵值Map??梢允褂米⑨尩膋eyColumn元素自定義此附加列名稱@MappedCollection: public class MyEntity { @Id Integer id; @MappedCollection(idColumn = "CUSTOM_COLUMN_NAME", keyColumn = "CUSTOM_KEY_COLUMN_NAME") List name; } public class MySubEntity { String name; } 9.6.7. 嵌入實(shí)體 嵌入式實(shí)體用于在 Java 數(shù)據(jù)模型中包含值對(duì)象,,即使數(shù)據(jù)庫(kù)中只有一張表,。在下面的示例中,您會(huì)看到它MyEntity與@Embedded注釋映射,。這樣做的結(jié)果是,,在數(shù)據(jù)庫(kù)中應(yīng)該有一個(gè)my_entity包含兩列id和name(來(lái)自EmbeddedEntity類)的表。 但是,,如果該name列實(shí)際上null在結(jié)果集中,,則整個(gè)屬性embeddedEntity將根據(jù)onEmptyof設(shè)置為 null @Embedded,null當(dāng)所有嵌套屬性都為 時(shí),,該s 對(duì)象null,。 與此行為相反,USE_EMPTY嘗試使用默認(rèn)構(gòu)造函數(shù)或從結(jié)果集中接受可為空參數(shù)值的構(gòu)造函數(shù)創(chuàng)建新實(shí)例,。 Example 57. 嵌入對(duì)象的示例代碼 public class MyEntity { @Id Integer id; @Embedded(onEmpty = USE_NULL) EmbeddedEntity embeddedEntity; } public class EmbeddedEntity { String name; } Null?embeddedEntity如果name在null,。用于使用屬性的潛在值進(jìn)行USE_EMPTY實(shí)例化。embeddedEntitynullname 如果您在一個(gè)實(shí)體中多次需要一個(gè)值對(duì)象,,這可以通過(guò)注釋的可選prefix元素來(lái)實(shí)現(xiàn)@Embedded,。此元素表示一個(gè)前綴,并為嵌入對(duì)象中的每個(gè)列名稱添加前綴,。 利用快捷方式@Embedded.Nullable& @Embedded.Emptyfor@Embedded(onEmpty = USE_NULL)和@Embedded(onEmpty = USE_EMPTY)來(lái)減少冗長(zhǎng),,同時(shí)相應(yīng)地設(shè)置 JSR-305 @javax.annotation.Nonnull。 public class MyEntity { @Id Integer id; @Embedded.Nullable EmbeddedEntity embeddedEntity; } 的快捷方式@Embedded(onEmpty = USE_NULL),。 包含 aCollection或 a 的嵌入實(shí)體Map將始終被視為非空,,因?yàn)樗鼈冎辽賹占匣蛴成洹R虼?,null即使在使用 @Embedded(onEmpty = USE_NULL) 時(shí),,這樣的實(shí)體也永遠(yuǎn)不會(huì)出現(xiàn)。 9.6.8. 實(shí)體狀態(tài)檢測(cè)策略 下表描述了 Spring Data 提供的用于檢測(cè)實(shí)體是否為新實(shí)體的策略: 內(nèi)容提示:本文(Spring Data JDBC參考文檔)未完待續(xù)...... |
|