What is the difference between spring.jpa.hibernate.hbm2ddl and spring.jpa.hibernate.ddl?
I have found in this question: What are the possible values of spring.datasource.initialization-mode? that OP is using both in properties, however it seems like the origin of hbm2ddl is hibernate directly not Spring Data Jpa.
Nevertheless, reading the answer from another OP, it looks like pass-through only.
However in our commercial project with mariadb, when we do not close our spring boot application gracefully with spring.jpa.hibernate.hbm2ddl.auto=create, when the application is run again, it deletes old data and creates everything from scratch. On the other hand with spring.jpa.hibernate.ddl.auto=create every second run (after no graceful application shutdown) causes key constraint exceptions (DB is not being dropper before creation)
From this Link
By default, JPA databases are automatically created only if you use an embedded database (H2, HSQL, or Derby).
You can explicitly configure JPA settings by using spring.jpa.* properties. For example, to create and drop tables you can add the following line to your application.properties:
spring.jpa.hibernate.ddl-auto=create-drop
Hibernate’s own internal property name for this (if you happen to remember it better) is hibernate.hbm2ddl.auto.
From this Link
spring.jpa.hibernate.ddl-auto This is actually a shortcut for the "hibernate.hbm2ddl.auto" property.
Defaults to "create-drop" when using an embedded database and no schema manager was detected. Otherwise, defaults to "none".
From this Link
Spring Boot can automatically create the schema (DDL scripts) of your DataSource and initialize it (DML scripts).
It loads SQL from the standard root classpath locations: schema.sql and data.sql, respectively.
In addition, Spring Boot processes the schema-${platform}.sql and data-${platform}.sql files (if present), where platform is the value of spring.datasource.platform.
This allows you to switch to database-specific scripts if necessary. For example, you might choose to set it to the vendor name of the database (hsqldb, h2, oracle, mysql, postgresql, and so on).
Related
I have a Spring Boot app that is configured to use JPA and its default-provider Hibernate. The app, in environment Non-Local, expects, and, through Oracle, is configured to connect to, an existing SQL DB, while the app, in environment Local, must, through H2, create it...embedded, in-memory, and private.
The DB utilizes one schema, as seen in this entity:
#Entity #Table(schema="foo",name="transactions")
Environment Local must, and is configured to, create (after first dropping any existing) tables and their schema. It is the creation, and dropping, of the latter - schema - that exhibits a problem:
Hibernate: drop table if exists foo.foo_transactions CASCADE
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "drop table if exists foo.foo_transactions CASCADE " via JDBC Statement
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Schema "FOO" not found; SQL statement: drop table if exists foo.foo_transactions CASCADE [90079-200]
...and a similar one (Schema not found) for CREATE.
So as to ensure no overlap, in the classpath, between H2 and Oracle, I, in the POM, separate them by build-profile (local and non-local):
<profile><id>local</id>...<dependencies><dependency>H2</dependency></dependencies>
<profile><id>non-local</id>...<dependences><dependency>Oracle</dependency></dependencies>
My relevant configuration of Spring Boot is:
# file application.properties
spring.datasource.url=jdbc:oracle:thin...
# file application-local.properties
# blankness of following value masks default configuration, in application.properties
spring.datasource.url=
spring.jpa.properties.javax.persistence.schema-generation.create-database-schemas=true
That JPA-property, javax.persistence.schema-generation.create-database-schemas, is supposed to do EXACTLY what I desire: create, in addition to tables, any internal schema. Yet, as shown in the aforementioned errors, it doesn't work!
Does H2, or the combination of H2, JPA-provider Hibernate, and Spring Boot, not honor it??? Or, have I miscoded/misconfigured something?
I don't want to get bogged down in the following (as the preceding question is my main concern), but for full disclosure...
P.S. If I remove the schema and build and run locally, everything works fine. But, the non-local (Production) flavor mandates that schema, so I must comply, and wish to do so also locally.
P.P.S. I am, indeed, aware of H2's directive 'INIT=CREATE SCHEMA IF NOT EXISTS foo' (to be applied to the datasource URL), and it, if used, does alleviate the problem. However, if I do use it (thereby having to explicitly supply a url, thereby conceding Spring Boot's very nice and full auto-configuration [of H2]), it causes another problem, which I need to avoid:
2022-08-29 15:43:27.494 WARN 15288 --- [on(5)-127.0.0.1] o.s.b.f.support.DisposableBeanAdapter: Invocation of destroy method failed on bean with name 'inMemoryDatabaseShutdownExecutor': org.h2.jdbc.JdbcSQLNonTransientConnectionException: Database is already closed (to disable automatic closing at VM shutdown, add ";DB_CLOSE_ON_EXIT=FALSE" to the db URL) [90121-200]
P.P.P.S. Neither that recommendation (...;DB_CLOSE_ON_EXIT=FALSE) nor its sister (...;DB_CLOSE_DELAY=-1) nor their combination alleviate that problem (attempt to close an already-closed DB).
I've now figured it out - my relevant JPA-property, at least as far as Hibernate is concerned, was slightly wrong...
Whereas I used (as it had once worked for me in EclipseLink, lazily leading me to believe that it was generic to all JPA-providers)
javax.persistence.schema-generation.create-database-schemas
I should have used this
javax.persistence.create-database-schemas
I'm trying to make Spring Boot application with Flyway (and Hikari pool) to start the server even when the DB is not available at that time.
I need to support cases when:
1. DB is not available when applicaition starts (it should run Flyway after DB starts, it can be up to 30 mins).
2. DB goes offline during the application lifetime and then goes back up.
I got a problem with the first case, Flyway always tries to do migrations even when DB is not available and application stops.
I tried adding spring.datasource.continue-on-error: true but Flyway ignores that, and I couldn't find any flyway configuration that would allow such operation.
Is it possible or should I wrap Flyway and do it myself?
Spring boot 2.1.4
A couple of points to consider
What is the desired behavior of the application when the DB is really not available when the instance of java application? Ok, so flyway won't start, but how the application will be able to handle requests that will have to reach the database?
Flyway itself relies on DataSource bean, maybe on hibernate if you use it, and these are much more complicated infrastructures than flyway itself?
Maybe if the database is not available the application won't need to start at all?
Instead it worth to rely on orchestrators (like kubernetes, ECS or whatever that will recognize that the application didn't start and will try to retrigger the start again, again, and again till the database will be ready)?
This is my recommendation in general.
Now, assuming find answers to all these questions and still, want to proceed with this path:
Spring Boot by itself works like this when it comes to flyway integration:
If the relevant classes (Flyway class) exist on classpath and spring.flyway.enabled=true then the bean of flyway starts and spring boot does its magic.
Technically the relevant auto configuration can be found in class org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration (org.springframework.boot:spring-boot-autoconfigure module)
I think the way to go is to disable flyway, and given that fact that beans like DataSource are available (somehow) - create a Flyway Bean by yourself and trigger the migration in some kind of loop in the background that will exit only if the migration actually succeeds (or already applied)
Specification
Each tenant has their own database which handles users in greater detail, and there needs to exist a central database which handles:
Tokens (OAuth2)
Users (limited level of detail)
Mapping users to their database
Problem
I've found solutions for multi-tenancy which allows me to determine the datasource depending on the user. However, I'm not sure how I can also link certain crud repositories to this central datasource, and others to variable datasources.
Another solution involved updating the properties file, and using a configuration server (i.e. via git) to trigger #RefreshScope annotated configs. Though I'm not sure if this can work for Datasources, or if this could cause problems later on.
Extra Context
I'm using Spring Boot and Hibernate heavily in this project.
This blog gives a very good tutorial on how to do it.
After a lot of research it looks like hibernate just isn't built for doing that, but by manually writing the schema myself I can inject that into new tenant databases using native queries.
I also had a problem with MS Server DBs, as they don't allow simply appending ;createDatabaseIfNotExist to the JDBC URL, which meant even more native queries (Moving the project over to use MySQL anyway, so this is no longer a problem.)
I'm using Spring Boot and JDBC for my database connection. I placed schema.sql at the classpath to initialize a schema and tables.
Because the schema doesn't exist yet while connecting to the datasource, I have to configure the datasource in application.properties like so:
spring.datasource.url=jdbc:mysql://localhost:3306/
schema.sql:
CREATE DATABASE IF NOT EXISTS <schema_name>
USE <schema.name>;
CREATE TABLE...
So I select the schema after creating it. This obviously doesn't persist for too long.
How do I configure this properly? Is there a way to select a default schema after the create script or maybe change the datasource url?
With JDBC you need to use Connection.setCatalog to switch between databases. You should not use USE <databasename> as the JDBC driver itself needs to be aware of which database it is operating on.
Based on your code from the schema.sql
USE <schema.name>;
This will not work for your java environment. The schema.sql will be executed and finished, which will not cater your requirement to set the default schema.
The General approach will be to use JDBC URL as;
jdbc:mysql://localhost:3306/DB_NAME
This will set the default db as DB_NAME.
Assumptions: I am assuming that you want to connect to single node DB without any loadbalancer or failover mechanism to be used. URL may change based on these features to be configured.
If you are not specifying the DB_NAME in the URL, it means their is no default schema.
You have 2 options to access the DB in that case.
1) Always use the Connection.setCatalog() method to specify the desired database in JDBC applications, rather than the USE database statement.
2) fully specify table names using the database name (that is, SELECT dbname.tablename.colname FROM dbname.tablename...) in your SQL. Opening a connection without specifying the database to use is generally only useful when building tools that work with multiple databases, such as GUI database managers.
For more details refer to the below mysql portal for reference.
https://dev.mysql.com/doc/connector-j/en/connector-j-reference-configuration-properties.html
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.