javascript
Spring Data JPA 从入门到精通~Naming命名策略详解及其实践
?Naming 命名策略詳解及其實踐
用 JPA 離不開 @Entity 實體,我都知道實體里面有字段映射,而字段映射的方法有兩種:
- 顯式命名:在映射配置時,設置的數據庫表名、列名等,就是進行顯式命名,即通過 @Column 注解配置。
- 隱式命名:顯式命名一般不是必要的,所以可以選擇當不設置名稱,這時就交由 Hibernate 進行隱式命名,另外隱式命名還包括那些不能進行顯式命名的數據庫標識符,即不加 @Column 注解時的默認映射規則。
Naming 命名策略詳解
我們通過源碼發現:Naming 的源碼發現 Hibernate 4 的時候隱式命名策略是 org.springframework.boot.orm.jpa.hibernate.SpringNamingStrategy;而我們發現 Hibernate 5 將隱式命名策略拆分成了兩步:implicitStrategy 和 physicalStrategy。從官方的文檔中得知這樣做的目的是提高靈活性,減少構建命名策略過程中用到的重復的信息。
- 第一個階段是從對象模型中提取一個合適的邏輯名稱,這個邏輯名稱可以由用戶指定,通過 @Column 和 @Table 等注解完成,也可以通過被 Hibernate 的 ImplicitNamingStrategy 指定。
- 第二個階段是將上述的邏輯名稱解析成物理名稱,物理名稱是由 Hibernate 中的 PhysicalNamingStrategy 決定,兩個階段是有先后順序的。
(1)ImplicitNamingStrategy
當一個實體對象沒有顯式的指明它要映射的數據庫表或者列的名稱時,在 Hibernate 內部就要為我們隱式處理,比如一個實體沒有在 @Table 中的指明表名,那么表名隱式的被認為是實體名,或者 @Entity 中的提供的名稱。比如一個實體沒有在 @Column 中的指明列名,那么列名隱式的被認為是該實體對應的字段名,而我們看到源碼默認的隱式策略采用的類是:“org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy”。
Hibernate 中定義了多個 ImplicitNamingStrategy 的實現,可以開箱即用,而之前的邏輯名名稱就是物理名稱這種策略只是其中一種,其他還包括:
- ImplicitNamingStrategyJpaCompliantImpl:默認的命名策略,兼容 JPA 2.0 的規范;
- ImplicitNamingStrategyLegacyHbmImpl:兼容 Hibernate 老版本中的命名規范;
- ImplicitNamingStrategyLegacyJpaImpl:兼容 JPA 1.0 規范中的命名規范;
- ImplicitNamingStrategyComponentPathImpl:大部分與 ImplicitNamingStrategyJpaCompliantImpl,但是對于 @Embedded 等注解標志的組件處理是通過使用 attributePath 完成的,因此如果我們在使用 @Embedded 注解的時候,如果要指定命名規范,可以直接繼承這個類來實現。
看一下 UML 類圖:
SpringImplicitNamingStrategy 繼承 ImplicitNamingStrategyJpaCompliantImpl,從源碼可以看到,對外鍵、鏈表查詢、索引如果未定義,都有下劃線的處理策略,而 table 和 column 名字都默認與字段一樣。
(2)PhysicalNamingStrategy
在這個階段中,是根據業務需要制定自己的命名規范,通過使用 PhysicalNamingStrategy 可以實現這些規則,而不需要將表名和列名通過 @Table 和 @Column 等注解顯式指定,無論對象模型中是否顯式地指定列名或者已經被隱式決定,PhysicalNamingStrategy 都會被調用。但是對于 ImplicitNamingStrategy,僅僅只有當沒有顯式地提供名稱時才會使用,也就是說當對象模型中已經指定了 @Table 或者 @Entity 等 name 時,設置的 ImplicitNamingStrategy 并不會起作用。
所以可以看應用場景,我們可以根據實際需求來定義自己的策略是繼承 ImplicitNamingStrategy 還是繼承 PhysicalNamingStrategy,比如加上前綴 t_ 等等,或者使用分隔符“-”等等。
需要注意的是:PhysicalNamingStrategy 永遠是在 ImplicitNamingStrategy 之后執行的,并且永遠會被執行到。我們看下 PhysicalNamingStrategyStandardImpl 的源碼:
public class PhysicalNamingStrategyStandardImpl implements PhysicalNamingStrategy, Serializable {public static final PhysicalNamingStrategyStandardImpl INSTANCE = new PhysicalNamingStrategyStandardImpl();@Overridepublic Identifier toPhysicalCatalogName(Identifier name, JdbcEnvironment context) {return name;}@Overridepublic Identifier toPhysicalSchemaName(Identifier name, JdbcEnvironment context) {return name;}@Overridepublic Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {return name;}@Overridepublic Identifier toPhysicalSequenceName(Identifier name, JdbcEnvironment context) {return name;}@Overridepublic Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) {return name;} }默認情況下,使用就是這種策略,將 ImplicitNamingStrategy 傳過來的邏輯名直接作為數據庫中的物理名稱,什么都沒干直接返回??聪骂悎D:
實際工作中的一些擴展
實際工作中,我們有這樣的應用場景:當我們使用 MySQL 數據庫的時候,一般架構師會給我們定義規范和要求,字段一般都是小寫加 "_" 下劃線組成,而我們的 Java 類當中都是駝峰式的字段命名方式。如果我們一個新的微服務,每個表都非常標準和規范,那么就可以讓實體當中省去 @column 指定名稱的過程。
定義自己的 PhysicalNamingStrategy 繼承 PhysicalNamingStrategyStandardImpl 類即可內容如下:
package com.jack.model.naming; public class MyPhysicalNamingStrategy extends PhysicalNamingStrategyStandardImpl { //重載PhysicalColumnName方法,修改字段的物理名稱。@Overridepublic Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) {String text = warp(name.getText());if(Objects.equals(text.charAt(0) , '_')){text = text.replaceFirst("_","");}return super.toPhysicalColumnName(new Identifier(text,name.isQuoted()), context);} //將駝峰式命名轉化成下劃線分割的形式public static String warp(String text){text = text.replaceAll("([A-Z])","_$1").toLowerCase();if(Objects.equals(text.charAt(0) , '_')){text = text.replaceFirst("_","");}return text;} }修改 application.properties 添加如下內容即可:
spring.jpa.hibernate.naming.physical-strategy=com.jack.model.naming.MyPhysicalNamingStrategy
總結:
不過在實際工作中還是建議大家用顯式 @Table @Column 等注解的時候就指明比較好,而可以在我們擴展的 MyPhysicalNamingStrategy 做規則驗證工作,避免有些程序員沒有按照我們的數據庫規范命名。
H2 Database
H2 Database?是一個開源的嵌入式數據庫引擎,采用 Java 語言編寫,支持 SQL,同時 H2 提供了一個十分方便的 Web 控制臺用于操作和管理數據庫內容。是一種內存數據庫,Spring Data JPA 官方也推薦使用,不過作者建議讀者在實際生產環境,我們都是用來跑測試用例的。這樣可以對各種關鍵的 DB 沒有影響,因為它是每次運行創建一份新的數據庫的。
使用起來比較方便,不需要安裝 Server 和 Client 的任何軟件和工具,只需要我們用的時候引用一個 Jar 就可以自帶 SQL 的 Server 和 Client 的操作了,非常適合演示項目使用。
我們來看一個使用案例。
(1)Gradle 引入 H2 的 jar 包
testCompile group: 'com.h2database', name: 'h2', version: '1.3.148'
(2)配置 application.properties 如下:
//# JDBC Url to use H2 DB File for persisting spring.datasource.url:jdbc:h2:./database/samspledb;AUTO_SERVER=TRUE //# Use H2 DB Driver spring.datasource.driverClassName:org.h2.Driver(3)其他什么都用改,直接啟動項目就可以操作我們默認的 JPA @Entity了。
spring.jpa.hibernate.ddl-auto=update
我們再加上 ddl-auto 的配置成 update,就可以完美實現內存數據庫方式的 test case 了。
總結
以上是生活随笔為你收集整理的Spring Data JPA 从入门到精通~Naming命名策略详解及其实践的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 扩展立方体 The Scale Cube
- 下一篇: javascript 数字精度问题