I have a Spring boot application that uses JPA with Hibernate. It already connect to a primary data source for all transactions.
Now the task in hand is that I need to dynamically create Database Schema in a different database. For instance,
For project 1, create schema 1 in Database X
For project 2, create schema 2 in Database X
Later, these databases will be used by others externally. I am looking for the best way to get this done.
In case of defining multiple datasources in spring boot project, you have to declare associated beans in your configuration. With spring.jpa.hibernate.ddl-auto=create it will automatically create the schema in right database as answered here
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"
I need to to change the spring batch application where I don't need to persist in the spring batch metadata tables, instead I need to use the in memory metadata.
My application is not Spring-Boot application, and I am using java configuration for spring.
Also I need to persist into the application tables so I need to use datasource.
Add in-memory DB to your Gradle project dependencies, for example, h2 :
compile 'com.h2database:h2:1.4.194'
Batch automatically will store the metadata in h2.
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.
The application has 2 separate databases, say:
DB1
DB2
and database of different companies are split across these 2 databases, like:
DB1
Company 1
Company 2
Company 3
Company 4
DB2
Company 5
Company 6
Company 7
Company 8
How can such a scenario be configured in hibernate?
All the examples refer either to Schema based multitenancy or Database multitenancy.
Is there any way to configure such a scenario?
To do that you should create two sessionFactory Bean in your config file. and in your DAO layer you call it using qualifier annotation.
You're going to have to create your own implementation of MultiTenantConnectionProvider that handles both database and schema level multitenancy. That should be the path of least resistance.
Here's some slightly outdated info about fighting with spring, hibernate and custom multitenancy: Setting up a MultiTenantConnectionProvider using Hibernate 4.2 and Spring 3.1.1
I will get strategy with separate database and in ConnectionProvider override method getConnection() to set schema.
I this case I can change databases and select specyfic schema for tenant.
do someone of you know a way to have 2 Databases running parallel?
We are using Hibernate 4 and as a main database Postgres 9.3 - this db is hosted on another machine then the application - if the database is down we still have to save some stuff.
So first intention was to write it into a csv, but I'm not a friend of writing stuff into an unordered file. So I want just to use a fallback Database (thinking of H2 Database). Does someone has experience with such a construct?
We are also using Spring 4 - I would just set up another datasource + sessionfactory + transactionmanager - and add the name at the #Transactional method to use the right manager. any other ideas?
Thank you!!
You can extend the Spring AbstractRoutingDataSource and configure two actual data sources:
a primary PostgreSQL data source
a secondary H2 data source
The application logic will see only one data source, which is the router which will decide which data source is going to switch to on demand.
When the primary data source is down you need to instruct the router to pick the fall-back H2 one.