We have a multi-tenant Spring Web app setup with Hibernate as JPA. We use a tenant per schema. We like to use tools like Envers or JaVers for Audit logging such that every db schema has its own audit tables.
How have you implemented this? Or would you implement it?
I have changed the code of JaVers a bit such that when it retrieves the db schema I will return the db schema that belongs to the logged-in user. This works partly as some tables are contained in the shared public schema, however, currently at the place were JaVers retrieves the db schema I don't have this entity/table info. I am thinking about changing JaVers code further such that I have this entity/table info, but isn't there a better library/approach to support multi-tenant?
Sorry for not posting any code 🙈
Related
I am a newbie that only knows basics of Java Core. I have test task where I need to create simple REST Web Service with Spring Boot.
I wrote all the logic in Java Core, and now I try to wrap it in all these technologies.
I am using this guide:
https://spring.io/guides/tutorials/rest/
Here they have JPA entities and #Table annotation, where table name is specified, but there are no SQL scripts to create tables in this guide.
So I thought JPA will create database and tables for entities by itself, but when I uncomment #Table annotation it says "Cannot resolve table '<table_name>'"
I am using IntelliJ IDEA with Spring Boot Maven project with imported Spring Web, H2 and JPA (like the guide tells to do).
I also configured H2 Data Source and tested the connection: works fine. There is a schema, but no tables.
Here is my application.properties:
spring.h2.console.enabled=true
spring.h2.console.path=/h2_console
spring.datasource.url=jdbc:h2:~/kaylemains
spring.datasource.platform=h2
spring.datasource.initialization-mode=always
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driverClassName=org.h2.Driver
spring.jpa.generate-ddl=true
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto = update
spring.jpa.show-sql=true
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
As in the guide, I add entities in LoadDatabase class like this:
#Bean
CommandLineRunner initTournaments(TournamentRepository repository) {
return args -> {
log.info("Preloading " + repository.save(new Tournament("Kayle Mains Competition: Summoner's Gorge", 16)));
};
}
So my question is: can I have file-stored H2 database and do everything with the it (including table creation) from my Java code?
OR it is necessary to create tables manually (by writing SQL scripts with CREATE TABLE) and construct them so that all entities work fine? (that means defining foreign key columns etc.), and only after that will JPA be able to work with this database? Do I need to add #Column annotation to every field, and JPA won't do it by itself for its Entities?
Why am I getting this error of "Cannot resolve table"? Of course it cannot be resolved because it does not exist yet, I thought JPA & Hibernate will create it for me based on entity classes...
Here in Baeldung you have all the information about the properties to ddl generation
Spring provides a JPA-specific property which Hibernate uses for DDL generation: spring.jpa.hibernate.ddl-auto.
create – Hibernate first drops existing tables, then creates new tables
update – the object model created based on the mappings (annotations or XML) >is compared with the existing schema, and then Hibernate updates the schema >according to the diff. It never deletes the existing tables or columns even if >they are no more required by the application
create-drop – similar to create, with the addition that Hibernate will drop >the database after all operations are completed. Typically used for unit testing
validate – Hibernate only validates whether the tables and columns exist, otherwise it throws an exception
none – this value effectively turns off the DDL generation
We have to set the value carefully or use one of the other mechanisms
to initialize the database.
If the problem is still present go to Settings -> Inspections, and uncheck the option "Unresolved database references in annotation"
After several readings about multi tenancy and how to implement it. I finally got my application working using Spring boot 2, Jpa and hibernate.
What I have for now is a schema per tenant architecture and every request use an X-tenantID header key to define the tenant from which the data should be queried.
Once I tried to implement security I found myself limited by this header key. What I want to achieve is to have a shared tenant where I should store all my users with the tenant identifier for each one of them, along with some other informations that should be used from all tenants. If it's possible how can I achieve such behavior? Is there a github project reference ? If a solution like eclipselink is proposed can you please reference an article explaining it's integration with spring boot?
The second question is how to create at runtime a new schema in database once a use is registered? A sample code or a documentation reference should be very welcomed.
Thanks
My application is as follows:
Spring 4, Spring MVC, Spring Data JPA, Hibernate 5.0.12
DB2 as database
Websphere 16 as server
Also is my web application multi-tenant based on schema. The implementation is almost like this: http://stuartingram.com/2016/10/02/spring-boot-schema-based-multi-tenancy/
Everything is working fine with multi-tenant when a user does CRUD operations on entities but when I try to seed some data on startup (ContextRefreshedEvent) the data is not inserted to the schemas.
But a previous request if data is in there, gives the right results that no data is there. I need to add here that one schema has already the seeded data.
The procedure is as follows:
Set tenant and with this the schema of the database
check if repository count is 0
if this is the case, create a new entity
save the new entity
The result of point 1 is correct, and there is no exception when the entity is saved (3). But there is no data in the database after the seeding.
Also is the tenant and schema correctly set before the repository methods are called.
A normal saving after the startup in a schema is successful.
What could be the reason why saving data to different schemes is not working before the application started completely?
Edit:
I tested the Code also on a Tomcat 8.5.4 and it is working. So there is something different in the implementation concerning WebSphere in Spring/Hibernate I guess.
I have a spring boot application with java 8 ,jpa etc and a jboss application with j2ee applications which calls too many sql procedures to update the table.
I have a query something like this in spring boot to get all the employee:
#Cacheable("employeeList")
List{Employee} findByAddressId(Long addressId);
But if someone inserts a new record to Employee table in the same address id from sql procdure from jboss application, the spring boot application is not able to pick the new records , because the query is so generic to that address id.
So i want to create a trigger on that table on insert and update , so when ever insert/update happens it should update the cache with new records belongs to that address id.
Can somebody please tell me how to do this?
If I understand the question correctly you have a spring boot app and a separate jboss app that are connecting to the same database and are insert/updating to the same database tables.
With spring's #Cachable you need to be able to tell spring when you should evict the cached item. For example, having the method that updates the entity being marked as #CacheEvict is an easy way to evict the entity from the cache. The problem here is that if the jboss app updates a record there is no way for spring boot app to know this.
Using a database trigger would seem problematic since you'd have to somehow have the db trigger communicate to the spring boot app to allow eviction to happen.
One solution may be having both the jboss and spring boot app use a distributed caches, like ehcache with terracotta.
as the title says, I have an application (Spring Boot) which must execute some queries on specified objects on a SQL Server database. Such database having a single catalog and multiple schemas, which must be selected based on a previous query and some command line parameters.
I cannot seem to implement a strategy which involves Hibernate multi-tenancy, as most of the tutorials and answers on this site deal with schema names coming from a web request or an external parameter, while I need a database connection before creating the main multi-tenant EntityManager. So, I switched to a custom DataSource which tries to change the connection's default schema (using ALTER USER... WITH DEFAULT_SCHEMA = ...). But this also fails because the logged-in user does not have permission to alter his own default schema.
So I'm at a loss of what to do. Any suggestions?
Just create an EntityManager(Factory) per schema and put them in a map to choose from.
If you don't know the schemas before hand you can create EntityManager(Factory)s as soon as you learn about a schema.
that you can configure an EntityManagerFactory programatically.