自定义物理命名策略

将我们的实体映射到数据库表名时,我们依赖于 @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")