can not run springboot junit tests with globally quoted identifiers - spring-boot

I've got an app that runs with spring.jpa.properties.hibernate.globally_quoted_identifiers=true. The database changes are managed through liquibase and the app uses a mysql database.
The problem is that when I try and run my junit tests, which use a hsqldb, I get the following exception when a repository call is made:
Caused by: java.sql.SQLSyntaxErrorException: unexpected token: in statement
I believe this is because we're not currently setting a default schema, so it's running it without a schema but the liquibase created the tables in PUBLIC schema. I tried setting spring.liquibase.default-schema=SCHEMA in my test properties to be the same schema as my prod properties, but then liquibase gets
liquibase.exception.DatabaseException: invalid schema name: SCHEMA in statement [CREATE TABLE SCHEMA.DATABASECHANGELOGLOCK
Because the schema hasn't been created yet in the HSQLDB.
Adding:
spring.jpa.hibernate.ddl-auto=update
spring.datasource.schema=classpath:test-schema.sql
where test-schema.sql is just CREATE SCHEMA IF NOT EXISTS schema; got me a bit further, but now when the tests run it tries to run some of the liquibase which runs a sql insert that is like INSERT INTO table without a schema attached, which fails. Unfortunately this changeset has already run against the actual app, so I can't really change it.
Is there a way to get spring.jpa.properties.hibernate.globally_quoted_identifiers=true along with setting the schema to work without getting rid of those changesets, or are the tests just totally hooped? Is there a way to get liquibase to run sql statements and automatically use the default schema for them?
If it helps, here is what my application-test.properties looks like:
spring.datasource.url=jdbc:hsqldb:mem:testdb;
spring.datasource.driver-class-name=org.hsqldb.jdbcDriver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
spring.liquibase.url=${spring.datasource.url}
spring.liquibase.change-log=classpath:db/changelog/db.changelog-test.xml
spring.liquibase.user=sa
spring.liquibase.contexts=test
spring.liquibase.password=
spring.liquibase.default-schema=schema
spring.jpa.hibernate.ddl-auto=update
spring.datasource.schema=classpath:test-schema.sql

Related

Spring JPA H2 and DB2 How to specify table schema to work on both databases

I am creating a Springboot app which I am planning to talk to DB2 database for production and to H2 database for development environments which I have setup using spring application.profiles.
My application.properties file also has setting:
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
, which if set, will not replace "." with "_" (as in MY_SCHEMA.CAR with MY_SCHEMA_CAR).
I need this since on DB2, I have to prefix table with schema like SELECT * FROM MY_SCHEMA.CAR. In H2 console, this is not needed and I can just do SELECT * FROM CAR.
However, I am running into following problem:
if my entity is annotated with #Table(name = "MY_SCHEMA.CAR") , I get DB2 error
error com.ibm.db2.jcc.am.SqlSyntaxErrorException: DB2 SQL Error:
SQLCODE=-551, SQLSTATE=42501, SQLERRMC=MY_USER;CREATE TABLE FOR USER
MY_SCHEMA;MY_SCHEMA.CAR, DRIVER=4.29.24. On H2, this creates table MY_SCHEMA.CAR.
if my entity is annotated with #Table(name = "CAR", schema = "MY_SCHEMA"), it works with DB2 but on H2, I get error
org.h2.jdbc.JdbcSQLSyntaxErrorException: Schema "MY_SCHEMA" not
found; SQL statement: create table MY_SCHEMA.CAR (...
How do I address issue in #2 above to get it working on my H2 database as well?
In general I prefer not to hardcode the default schema in the app. If the schema changes for any reason the app doesn't need to be affected.
To do that, remove the schema on the SpringBoot app. You'll need to change the JDBC connection URL, though. Append :currentSchema=MY_SCHEMA; to set the default schema.
For example, when connecting to DB2 in my sandbox I use:
jdbc:db2://192.168.56.218:50000/empusa:currentSchema=ECOS;
H2 offers a similar feature. When I connect to my H2 database I use:
jdbc:h2:tcp://localhost/~/test;SCHEMA=ECOS

Deprecated configuration property 'spring.datasource.initialization-mode'

This is going to be the spring back-end of a project that I am working on. I am able to create tables from my model classes in Postgres database however I wasn't able to put static data to the tables.
I created a data.sql file in resources with bunch of insert commands.
This is how my application.properties looks like:
spring.datasource.url=jdbc:postgresql://localhost:5432/springtest
spring.datasource.username=
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.properties.hibernate.format_sql=true
spring.datasource.initialization-mode=always
The compiler(Intellij) is crossing a line over
"spring.datasource.initialization-mode"
with the message:
Deprecated configuration property
'spring.datasource.initialization-mode'
It also suggest me to use the replacement key spring.sql.init.mode=always however this does not work as well. I need the program to execute the SQL commands in data.sql.
Since Spring Boot 2.5.0 by default, data.sql scripts are now run before Hibernate is initialized. This aligns the behavior of basic script-based initialization with that of Flyway and Liquibase. If you want to use data.sql to populate a schema created by Hibernate, set spring.jpa.defer-datasource-initialization to true.
Additional info: github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.5-Release-Notes
I was able to figure it out by changing
spring.datasource.initialization-mode=always
to
spring.sql.init.mode=always
and renaming data.sql to import.sql

Schema not found using Hibernate and Oracle

Right now I am running into an issue where I am getting "MySchema" not found exception:
org.h2.jdbc.JdbcSQLSyntaxErrorException: Schema "MySchema" not found; SQL statement:
select batchstatu0_.batch_key as batch_ke1_0_ from myschema.batch_status batchstatu0_ [90079-199]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:573)
at org.h2.message.DbException.getJdbcSQLException(DbException.java:427)
When I run the generated sql from Oracle SQL Developer using the same credentials, the select statement correctly finds the schema and runs the query.
One of the things I initially tried with success but not the solution I would like to go with was to specify a whole new DataSource for the specified schema. That worked but will be a serious headache when we start adding event more schemas. I would much rather use one Datasource and specify the schema in the Table annotations.
#Table(name="BATCH_STATUS", schema ="MySchema")
public class BatchStatus {
...
}
And the properties:
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
hibernate.show_sql=true
spring.datasource.jdbc-url=jdbc:oracle:thin:xxx
spring.datasource.username=xxx
spring.datasource.password=xxx
hibernate.default_schema=MySchema
I would assume this has to be some sort of config issue but I haven't been able to figure it out.
you need to specify
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
As per the exception, it is using H2 driver

Why I can't find my tables in H2 schema / How can I validate which H2 schema my Spring boot app is working with?

I'm running a spring boot app
didn't have any setting for h2 other than maven
when i'm connecting to the h2 console i can see the tables that were supposed to be created for two entities
i connected with the JDBC URL: jdbc:h2:mem:testdb (which is supposed to be the default)
Is there a way to make sure what schemas is H2 currently running/ or some log file for H2 ?
in my application.properties i have this:
spring.h2.console.enabled=true
spring.h2.console.path=/h2
I read somewhere that H2 initializing itself upon login, but a demo i was watching these were the exact steps taken , so not sure that is the case.
these are the settings in the H# console:
You can explicitly instruct spring boot to create and connect to a particular schema in H2 with config as below.
spring.datasource.url=jdbc:h2:~/test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=sa
This creates a datasource of name test database in h2 in file mode. There would be a file called test.db in your home folder which would be the data file for the database.
DB_CLOSE_ON_EXIT property decides to recreate the database on every restart.
There is an easier way to tell Spring JPA the default schema for your H2 data source by just adding the "SET SCHEMA {default schema}" in the datasource url, e.g.:
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS testdb\\;SET SCHEMA testdb
I actually saw the right schema all along
The reason I thought I wasn't seeing the right schema was - the JPA Entities I expected to see, were not there.
I then found that this was because I didn't name the package for the JPA entities correctly
I named it "domain" (see pic):
I should have named it com.example.domain as can be seen:
This is because Spring Boot looks is doing a #ComponentScan "under" the package with the main class , so I had to prefix the "domains" with the name of the package that the main class resides in, which is com.example.
For me I had to check the log when I run Sprinboot
jdbc:h2:mem:9967b201-6b59-4925-acb3-d2e50dc5d9a5. --> this can be any other auto generated UUD
Adding this to your JDPC URL in the browser will let you see the tables that you created.

How to see the schema sql (DDL) in spring boot?

How can I see the DDL SQL generated by Hibernate for building the schema from the JPA mappings? I am using the embedded HSQL db.
I tried the following and none of them worked in Spring-Boot 1.3.5.RELEASE.
Adding the following to application.properties file
debug=true
spring.jpa.properties.hibernate.show_sql=true
Set org.hibernate.SQL level to debug in logback.xml
Steps listed at http://docs.spring.io/spring-boot/docs/current/reference/html/howto-database-initialization.html
Those only show me the sql issued by Hibernate for queries. I am looking for the DDL schema sql issued by Hibernate due the following property:
spring.jpa.hibernate.ddl-auto=create-drop
Try with this property and value:
javax.persistence.schema-generation.scripts.action=create
Do not forget to also set this property:
javax.persistence.schema-generation.scripts.create-target=my-schema.sql
From the JPA 2.1 Specifiation, page 370:
javax.persistence.schema-generation.scripts.action
The javax.persistence.schema-generation.scripts.action property specifies
which scripts are to be generated by the persistence provider. The
values for this property are none, create, drop-and-create, drop. A
script will only be generated if the script target is specified. If
this property is not specified, it is assumed that script generation
is not needed or will
In Spring Boot you can define those two properties in your application.properties file:
spring.jpa.properties.javax.persistence.schema-generation.scripts.create-target=build/my-schema.sql
spring.jpa.properties.javax.persistence.schema-generation.scripts.action=create
Here is a blog post about JPA schema generation with further information about these and other properties:
http://www.thoughts-on-java.org/standardized-schema-generation-data-loading-jpa-2-1/

Resources