✅ Short Answer
- MultiTenantConnectionProvider is the Hibernate SPI that provides connections specific to each tenant, e.g., different schemas or databases.
- CurrentTenantIdentifierResolver tells Hibernate which tenant ID to use for the current request.
Together, they let Hibernate dynamically route connections and SQL statements to the correct tenant context.
🔎 Detailed Explanation
🔹 MultiTenantConnectionProvider
✅ It’s an interface you implement to supply JDBC connections appropriate for each tenant.
✅ Methods of interest:
getConnection(String tenantIdentifier)
→ returns a connection configured for the requested tenant.releaseConnection(String tenantIdentifier, Connection connection)
→ cleans up when done.
✅ Hibernate calls your MultiTenantConnectionProvider
whenever it needs a connection → your implementation decides how to get the right connection:
- For SCHEMA strategy → reuse one DataSource, but set the schema with
SET SCHEMA tenant_x
. - For DATABASE strategy → open connections from different DataSources, one per tenant.
✅ Example skeleton:
public class SchemaMultiTenantConnectionProvider implements MultiTenantConnectionProvider {
private final DataSource dataSource;
public SchemaMultiTenantConnectionProvider(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public Connection getConnection(String tenantIdentifier) throws SQLException {
Connection connection = dataSource.getConnection();
connection.createStatement().execute("SET SCHEMA '" + tenantIdentifier + "'");
return connection;
}
@Override
public void releaseConnection(String tenantIdentifier, Connection connection) throws SQLException {
connection.close();
}
// other required methods...
}
🔹 CurrentTenantIdentifierResolver
✅ Tells Hibernate which tenant identifier to use for the current request/session.
✅ It has a single important method:
String resolveCurrentTenantIdentifier();
✅ This is typically implemented by reading tenant information from:
- HTTP request headers
- ThreadLocal context
- Security context
✅ Example skeleton:
public class HeaderTenantIdentifierResolver implements CurrentTenantIdentifierResolver {
@Override
public String resolveCurrentTenantIdentifier() {
return TenantContext.getCurrentTenant(); // from ThreadLocal or request context
}
@Override
public boolean validateExistingCurrentSessions() {
return true; // allows reusing session if tenant ID doesn’t change
}
}
🔹 How do they work together?
1️⃣ A user makes a request → you determine tenant ID (e.g., from HTTP header).
2️⃣ CurrentTenantIdentifierResolver
returns the tenant ID to Hibernate.
3️⃣ Hibernate passes that tenant ID to MultiTenantConnectionProvider.getConnection(...)
.
4️⃣ Your provider returns the appropriate connection → either switching schema or connecting to the right DB.
✅ Hibernate then uses the returned connection for all operations in the current session.
🔹 Multi-tenancy strategies supported by Hibernate
✅ SCHEMA → one database, multiple schemas → SET SCHEMA
per tenant.
✅ DATABASE → multiple databases → different DataSource or connection pools per tenant.
✅ DISCRIMINATOR → one table with tenant_id column (simplest).
📌 Key Takeaways
✅ CurrentTenantIdentifierResolver → identifies which tenant is active for the current session/request.
✅ MultiTenantConnectionProvider → provides connections tied to that tenant.
✅ Together, they enable Hibernate’s multi-tenancy strategies, isolating tenant data at runtime.