how to manage dynamic tables with hibernate - multi tenant database - spring

I am using hibernate 3 using spring 3.5 for a SaaS application. I am expecting upto 10-15 customers , not more. I do not want to implement separate db or schema per customer as its too complicated and costly for a small enterprise like mine. I am currently using a multi-tenant strategy which works fine for a host of small features. Here is the use case where my design fails:
For reporting feature each customer will have a different table for data (because of various reasons like legacy, source of data etc). Table structure differs and so does service/controller behaviors.
I am currently planning to create separate Controllers, Services (DAOs), etc for each customer, thus mapping each of such customer tables with a separate hibernate class. But this approach is not clean and for every new customer I add (which is not that often though), I would need to add its table, and also code a hibernate entity class mapped to the new table, which is not ideal as it needs coding. Is there a way to manage/map such dynamic tables using hibernate which gets added when a new customer is added ?

Use Hibernate 4 multi-tenancy support, see the documentation here. There is support for separate databases per tenant, separate schemas per tenant and partitioning of the same table per tenant.

Is there a way to manage/map such dynamic tables using hibernate which
gets added when a new customer is added ?
I don't know if this is directly supported by Hibernate. From the manual, the supported multi-tenant options are:
schema
database
discriminator
Discriminator is mentioned but is not supported in the current release of Hibernate (version 4.2). That leaves schema and database. You mentioned in your question that neither of these are currently applicable to your setup. So unless you're willing to do some major restructuring, you'll probably need to proceed with a different approach.
Option 1:
If I were you, I'd write a view that presents the data from each tenant's table. You can add the tenant ID as a column in the view. Map the reporting class to the view with Hibernate. When you run a query against the view, set the current tenant's ID as a query parameter.
If you go this route, you won't need to add new controllers and POJOs when you add a customer. Just modify the view to also include the new customer's data and it should work.
Option 2:
Hibernate can bind native SQL query results to entities. You can have one entity that represents the data in any reporting table (this assumes that the separate per-customer tables have a similar structure).
In your reporting DAO, you'd fetch a SQL query from a properties file or specify a named SQL query based on the current tenant identifier. Note that the named query approach will only meet your needs (no recompilation of Java classes) if you have things mapped with HBM files. If your mapping is done with annotations, you'd need to rebuild the project to add a named query.

Related

Multiple databases (Postgresql in RDS) but same spring repository and entity

I have a use case where I need to create exact same postgresql database in two different regions. Everything is same in these two databases i.e same schema and same tables and same data.
I have a use to achieve distributed transaction. So if a request land in region-a and write to region-a database to let's say Person table, then exact same record must be either written in Person table in both these database or if there is any error, write attempt should be rolled back.
I am trying to figure out if I can attach two different datasources with same Person Entity and CRUD repository in spring so the respoistory.save() method can write to Person table in both the databases.
So far, I have come across AbstractRoutingDataSource but that is for achieving multi tenancy in the databases. Other solutions are found are slightly different where use case is to write different records in different database (mostly sharding based on various data points).
Does spring provide any out of the box solution so I can achieve transactional write to same table in two different databases.
Does spring provide any out of the box solution so I can achieve transactional write to same table in two different databases.
Depends on your definition of "out of the box" - it doesn't itself implement distributed transactions, but does have support for using libraries that do. It is however relatively complicated to get everything working correctly, and requires additional components to be carefully configured in your runtime environment.
Spring Boot 2.x documentation on distributed transactions is here: https://docs.spring.io/spring-boot/docs/2.7.x/reference/htmlsingle/#io.jta
The Spring Boot 3.x documentation is here: https://docs.spring.io/spring-boot/docs/current/reference/html/io.html#io.jta but it's also worth noting that for 3.x, the Spring Boot team have changed direction and decided that integrated support should be provided by the relevant JTA provider (cf. https://github.com/spring-projects/spring-boot/issues/28589 ), and so there's projects like https://github.com/snowdrop/narayana-spring-boot

Liquibase compare and update databases

I would like to use liquibase in my spring boot app. My requirement is that I have a dummy schema which is populated with tables every time I change the entity classes. This is done by hibernate's ddl create. There are many identical schemas to the dummy schema with data. I want those schemas to be compared with the dummy schema on update and be synced without affecting my data. How can I achieve this? I could not find a tutorial anywhere. If there is one please do give me the link.
I think this tutorial explains what your are looking for
baeldung maven liquibase plugin
In section 5.3 is a description on how you can get a changlog file with differences between two databases.

Javers - What are advantages of using Javers instead of Envers?

I am developing a RESTful API using Spring Data REST. Now for auditing, Spring does have the option to auditing meta data like created_date and modified_date but they don't provide entity versioning.
Currently there are two popular libraries for entity version which are Envers and Javers. I have looked over for a comparison of both but there arent any articles on this matter.
So what are the benefits and drawbacks of using Javers over Envers?
There are two big difference between JaVers and Envers:
Envers is the Hibernate plugin.
It has good integration with Hibernate but you can use it only with traditional SQL databases.
If you choosed NoSQL database or SQL but with other persistence framework like
JOOQ — Envers is not an option.
On the contrary, JaVers can be used with any kind of database and any kind of
persistence framework. For now, JaVers comes with repository implementations for MongoDB and
popular SQL databases. Other databases (like Cassandra, Elastic) might be added in the future.
Envers’ audit data model is a copy of application’s data model. As the doc says:
For each audited entity, an audit table is created.
By default, the audit table name is created by adding a _AUD suffix to the original name.
It can be advantage, you have audit data close to your live data. Envers’ tables look familiar.
It’s easy to query them with SQL.
JaVers uses its own Snapshot model for audit data.
Snapshots are decoupled from live data,
JaVers saves them to the single table (jv_snapshots) as JSON documents with unified structure.
Advantages? You can choose where to store audit data.
By default JaVers uses the same database as application does,
but you can point another database. For example, SQL for application and MongoDB for JaVers
or centralized JaVers database shared for all applications in your company).
Read this blogpost with full JaVers vs Envers comparison:
https://javers.org/blog/2017/12/javers-vs-envers-comparision.html
Enver is like git for a database.
I do not know Javers but a complete Envers databinding has this advantages:
A table is created in the database called REVINFO having a timestamp and a PK.
To every entity that is audited, one shadow-copy is created. Theese shadow-copies have every field nullable and the PK is not a PK. Theese shadow-copies have a new field, the reference to the table REVINFO.
This gives Enver the possibility to record changes that has been made in the past in this shadow-copies. You can move that shadow-tables into an different database.

How can I create an in-memory test database when the table mappings are using other databases?

I'm trying to create some tests for an application that uses Spring and JPA (with Hibernate).
I want to use an in-memory database so that I can check if everything is working without having to depend on the main development server (which is an old Sybase installation), and also will allow me to isolate better the tests functionality.
Problem is, there are a lot of tables that are mapped using #Table("dbname..dbo.someviewname") to access views from other databases.
So, I was trying to use HSQLDB with DBunit, but HSQLDB understandbly does not allow to create tables with dots in their names.
How can I do tests against that?
Should I give up of the in-memory thing and do tests using the main Sybase development server (risking to ruin it for the other devs :P)?
From dbname.dbo.someviewname HSQLDB likely extracts dbname as catalog, dbo as schema and somewiewname as table name.
HSQLDB do allow creating tables which have dot in their names. That can be done by treating table name as delimited identifier:
#Table(name="\"dbname.dbo.someviewname\"")
But you do not want to use that, because then how names are treated is changed also for Sybase. If you can have separate orm.xml for tests, then you can add following to orm.xml:
<persistence-unit-defaults>
<delimited-identifiers/>
</persistence-unit-defaults>
It causes all database object names to be treated as delimited identifiers. Depending about your mappings and queries it can eventually work, but most likely you will face some problems. Likely best approach is not to have schema names in mappings and/or separate Sybase instance for tests.

How to configure schema name for mapped entity / table in JPA / hibernate

I have an application which need to access 2 schemas at runtime, and the schema names need to be configured when deploy, because the name are different for each deployment (for assembly testing, integration testing, performance testing...)
I know JPA / hibernate can specify schema on #Table annotation, but I need to make the schema configurable, is there anyway to add a post processor / event listener so I can modify the hibernate meta info, and change the table schema with my configuration?
Currently I'm looking into rewrite my own HibernateJpaVendorAdapter / HibernatePersistence, but definitely this is not a good idea.
Thanks.
You might also want to investigate the persistence-unit-defaults element in your META-INF/orm.xml file. This allows you to specify a default schema and catalog for a persistence unit. That may or may not meet your needs, depending on how you figure out what schema to access in your code. Also be aware that Hibernate has been riddled with bugs in this area for years and years. Nevertheless, it might be better than writing custom code.

Resources