| MULTITENANCY APPROACH This solution is not a new multi-tenancy approach. It is a complement to the multitenancy "Separate Schema" approach, with option #2 : "SET SCHEMA command" as described here : https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#multitenacy-separate-schema GOAL It aims at providing additional tools for schema generation in two ways :
- better SchemaExport facilities allowing to export a SQL script for database schema creation using database/sequence filters
- better isolation of data using ddl-auto=create when automatically creating the database model on application startup in a development environment
EXAMPLE Let's consider my usage. In my multi-tenant application, I want some data to be isolated in tenant dedicated schemas (one for each tenant), and other data to be located in a common schema (those not specific to a tenant, including global configuration data). Let's consider a single database named "my-database" with data for two tenants named "a" and "b". The database has 3 schemas :
- *common *: the common schema with data not specific to a tenant
- *tenant_a *: the tenant "a" schema with its dedicated data
- *tenant_b *: the tenant "b" schema with its dedicated data
I think it is a very general use case for this tenant approach. With this database, I use the separate schema multi-tenant approach with option 2 : "SET SCHEMA" command, with postgreSQL. When a call is made by tenant "a", I set the search path with "set search_path=tenant_a,common" using my implentation of AbstractDataSourceBasedMultiTenantConnectionProviderImpl, and I do not provide a specific schema in entity classes annotations. Then, when the SQL request is send by Hibernate, the database automatically locates data in the right schema, testing first the tenant_a schema, then the common schema. All I have to do is to take care of using non conflicting table names between the common schema and the tenant specific schema. for additional information of PostgreSQL search_path, see : https://www.postgresql.org/docs/9.1/static/runtime-config-client.html So, all works correctly. But... THE LIMITATION I want to export a schema creation SQL script for each schema, one for the common data, to be run at system initialization, and one for the tenant specific schema to be run each time a new tenant is created. How do I export schema creation SQL scripts as there is no information in the code of what schema to be used ? Hibernate provides a filter tool for that based on the interface org.hibernate.tool.schema.spi.SchemaFilterProvider. To achieve this I have to implement this interface. But the provided arguments do not include entity class name. So, If I wish to filter entites, I have to write a big "swtich" with all class names. It is a hell for maintenance as each time I create a new entity I have to add it to the filter implementation. I tried to fix it using a provided schema for the common data, and considering all entities with no schema to be tenant specific. But I face the problem that I want to use the same common entity class in two applications with different named schemas, so I could not hard code the schema name in the entity class. I also face another problem using ddl-auto=create. When starting with this mode and the search_path set to "tenant_a,common", all entites using default schema are created in the first schema "tenant_a", including the common data. As this mode is very useful in development mode, I could not resign to give up with this mode. These two problems show that the solution lies in defining dynamical schema name, for each entity class, what schema name to be used at runtime. And it is easy to define it with a filter on the package name :
With this approach I can :
- tell SchemaExport how to filter exported tables and sequences, based on package name filter
- tell ddl-auto=create a specific schema name to start the application in development mode with data located in the right schema (using forced schema name for all entities).
My proposal could be summed as : "I would like to define dynamically the schema name to be used for each entity". From my usage example, this concept seams to me to be relevant. I am not an expert for the Hibernate code, so I hope you could help me to analyse it and maybe integrate it as a new feature I could rely using an "official" Hibernate version in production. Thanks. |