自定義物理命名策略

將我們的實體對映到資料庫表名時,我們依賴於 @Table 註釋。但是如果我們有資料庫表名的命名約定,我們可以實現一個自定義的物理命名策略,以告訴 hibernate 根據實體的名稱計算表名,而不用 @Table 註釋明確說明這些名稱。屬性和列對映也是如此。

例如,我們的實體名稱是:

ApplicationEventLog

我們的表名是:

application_event_log

我們的物理命名策略需要從 camel case 的實體名稱轉換為我們的 db 表名稱,這些名稱是 snake case。我們可以通過擴充套件 hibernate 的 PhysicalNamingStrategyStandardImpl 來實現這個目標:

import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;

public class PhysicalNamingStrategyImpl extends PhysicalNamingStrategyStandardImpl {

    private static final long serialVersionUID = 1L;
    public static final PhysicalNamingStrategyImpl INSTANCE = new PhysicalNamingStrategyImpl();

    @Override
    public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
        return new Identifier(addUnderscores(name.getText()), name.isQuoted());
    }

    @Override
    public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) {
        return new Identifier(addUnderscores(name.getText()), name.isQuoted());
    }

    protected static String addUnderscores(String name) {
        final StringBuilder buf = new StringBuilder(name);
        for (int i = 1; i < buf.length() - 1; i++) {
            if (Character.isLowerCase(buf.charAt(i - 1)) &&
                    Character.isUpperCase(buf.charAt(i)) &&
                    Character.isLowerCase(buf.charAt(i + 1))) {
                buf.insert(i++, '_');
            }
        }
        return buf.toString().toLowerCase(Locale.ROOT);
    }
}

我們正在重寫方法 toPhysicalTableNametoPhysicalColumnName 的預設行為以應用我們的資料庫命名約定。

為了使用我們的自定義實現,我們需要定義 hibernate.physical_naming_strategy 屬性並將其命名為 PhysicalNamingStrategyImpl 類。

hibernate.physical_naming_strategy=com.example.foo.bar.PhysicalNamingStrategyImpl

這樣我們就可以從 @Table@Column 註釋中減輕程式碼,所以我們的實體類:

@Entity
public class ApplicationEventLog {
    private Date startTimestamp;
    private String logUser;
    private Integer eventSuccess;

    @Column(name="finish_dtl")
    private String finishDetails;
}

將正確對映到 db 表:

CREATE TABLE application_event_log (
  ...
  start_timestamp timestamp,
  log_user varchar(255),
  event_success int(11),
  finish_dtl varchar(2000),
  ...
)

如上例所示,由於某些原因,我們仍然可以根據我們的一般命名約定明確說明 db 物件的名稱:@Column(name="finish_dtl")