In Hibernate, what is the difference between an ImplicitNamingStrategy and a PhysicalNamingStrategy, and when does each one run while the mapping model is built?
answer
- implicit = name when unnamed
- physical = every name to identifier
- annotated names skip implicit, not physical
- JPA-compliant default = property name verbatim
- two boot settings: implicit_/physical_naming_strategy
basics
~20 sImplicitNamingStrategy invents a logical name when the mapping does not state one (entity name, field name, join-table name). PhysicalNamingStrategy then turns every logical name - invented or explicitly annotated - into the actual database identifier Hibernate emits in SQL.
solid answer
~50 sHibernate names things in two passes. First it settles a logical name for every table, column, sequence, join table and constraint. If the mapping supplies one (@Table(name=...), @Column(name=...)), that is the logical name; if not, the ImplicitNamingStrategy derives it - the JPA-compliant default gives the unqualified entity name for tables and the property name for columns. Second, every logical name - derived or annotated - passes through the PhysicalNamingStrategy, which produces the identifier Hibernate actually writes into DDL and SQL. The shipped default is a pass-through. So implicit answers 'what do we call it when nobody said', physical answers 'how does any name become a database identifier'. That is why global conventions - camelCase to snake_case, a fixed prefix, length truncation - belong in the physical strategy: it is the only hook that also sees explicitly annotated names. Configure them with hibernate.implicit_naming_strategy and hibernate.physical_naming_strategy.
code
java · 7 linespublic class PrefixingPhysicalNamingStrategy extends PhysicalNamingStrategyStandardImpl {
@Override
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment env) {
if (name == null) return null;
return Identifier.toIdentifier("app_" + name.getText(), name.isQuoted());
}
}go deeper
Be able to say which hook names things you left unnamed and which one rewrites all names, and know the two configuration property names.
Explain the two-pass model precisely, including that annotated names still go through the physical strategy, and pick the right hook for a given convention.
Discuss consequences: schema migration when a strategy changes, quoting preservation in custom implementations, and constraint naming living in the implicit hook.
Frame it as governance - one boot-time strategy enforcing house conventions across many services beats per-entity annotations, and settle who owns identifier rules between developers and DBAs.
## Two different questions Turning Java identifiers into database identifiers hides two independent questions. 1. What is this thing called if nobody said? An entity class CustomerOrder with field createdAt and no name attributes still needs a table and a column name. 2. How is any chosen name spelled as a database identifier? Maybe every table gets a prefix, or camelCase must become snake_case, or the identifier must be truncated to 30 characters. Hibernate 5 split the old single NamingStrategy interface into exactly these two hooks, and Hibernate 6 keeps them. ## Pass 1: logical names and ImplicitNamingStrategy While reading annotations Hibernate builds a mapping model in which every table, column, sequence, join table, foreign key, unique key and index has a logical name. If the annotation carries a name, that string is the logical name. If it does not, Hibernate calls the ImplicitNamingStrategy: determinePrimaryTableName, determineBasicColumnName, determineJoinTableName, determineForeignKeyName and so on. The default is ImplicitNamingStrategyJpaCompliantImpl, which follows the JPA spec: table name = unqualified entity name; basic column = property name verbatim; a @ManyToOne join column = property name + underscore + referenced primary key column; a join table = owner table + underscore + other table. Nothing here lower-cases or de-camel-cases anything: field createdAt yields logical column createdAt. Other shipped variants exist (legacy-jpa, legacy-hbm, component-path, which prefixes embedded attributes with the component path) and you can supply your own class. ## Pass 2: physical names and PhysicalNamingStrategy Once the mapping model is complete, each logical name is handed to the PhysicalNamingStrategy: toPhysicalTableName, toPhysicalColumnName, toPhysicalSequenceName, toPhysicalSchemaName, toPhysicalCatalogName. Each receives an Identifier plus the JdbcEnvironment (dialect, identifier helper) and returns the Identifier to actually use. The crucial property is that this pass sees every name, including the ones you wrote by hand in @Column. The default PhysicalNamingStrategyStandardImpl returns the name unchanged, which is why out of the box the physical name equals the logical name and people forget the second pass exists. ## Why the distinction matters in practice When you want a house convention across the whole schema, you override the physical strategy: it is uniform, it also normalises hand-written names, and it cannot be forgotten on one entity. When you want to change only defaults - a naming rule for join tables or for foreign key constraints - you override the implicit strategy, because those names are only ever produced there. A second consequence: logical names are what Hibernate uses internally to resolve references across the mapping (for example @JoinColumn(name=...) refers to a logical column name), while physical names are what appears in SQL. JPQL and HQL are written against entity and attribute names, so neither strategy touches your queries - only the emitted SQL and DDL change. ## Configuration Both are boot-time settings: hibernate.implicit_naming_strategy (short names default, jpa, legacy-jpa, legacy-hbm, component-path, or an FQN) and hibernate.physical_naming_strategy (an FQN or instance). Because they run at bootstrap, changing them changes generated DDL and every emitted statement; against an existing schema you must migrate the schema to match.
- Which hook do you override to make the whole schema snake_case, and why is the other one the wrong place?The physical strategy, because it is applied to every logical name including the ones written explicitly in @Table and @Column, so the convention holds uniformly. An implicit strategy would only affect entities and fields that left the name out; the moment someone adds an explicit @Column the rule silently stops applying.
- Does the implicit strategy also name things other than tables and columns?Yes. It has methods for join tables, join columns, collection tables, discriminator and tenant-id columns, and for foreign key, unique key and index constraint names. Those names are only ever produced implicitly unless you annotate them, so a house convention for constraint names has to live in the implicit strategy.
- Do these strategies affect how you write JPQL?No. JPQL and HQL are written against entity names and attribute names, which come from the Java model, not from the physical identifiers. Naming strategies only change generated DDL and the SQL Hibernate emits, so switching strategy never requires editing a JPQL query - only migrating the database schema.
Implicit naming is the clerk who fills in a blank form field for you; physical naming is the printer that stamps every field - blank-filled or hand-written - into the house typeface.
saying these in an interview costs you the question
- Saying an explicitly annotated @Column name bypasses both strategies - it bypasses only the implicit one
- Claiming Hibernate converts camelCase to snake_case by default - the JPA-compliant default copies the property name verbatim
- Thinking the implicit strategy is the place to implement a global prefix or case convention
- Believing a naming strategy rewrites your JPQL identifiers as well as the SQL
- Assuming the strategies can be swapped at runtime per request - they are boot-time settings baked into the mapping model