Schema not found using Hibernate and Oracle - spring

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

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

can not run springboot junit tests with globally quoted identifiers

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

Error getting H2 with r2dbc running in Spring boot

for days now I've been trying to get a simple H2 / R2dbc database running in Spring boot with WebFlux. The app starts up just fine but when I call the /todos endpoint to get all the objects in the database I get the following error:
reactor.core.Exceptions$ErrorCallbackNotImplemented: org.springframework.data.r2dbc.BadSqlGrammarException: executeMany; bad SQL grammar [SELECT TODO.* FROM TODO]; nested exception is io.r2dbc.spi.R2dbcBadGrammarException: [42102] [42S02] Table "TODO" not found; SQL statement:
SELECT TODO.* FROM TODO [42102-200]
My understanding is that if I add a schema.sql file on the class path with a create table command it will use that to create the table on startup, but it does not look like that is working. Any ideas on what I may be doing wrong? Any help would be appreciated, what would like to get to is a working mysql/r2dbc example, if someone could point me to one.
All the code is located at: https://gitlab.com/vanfleet/test-r2dbc-h2
It is query issue. Run same query in editor.

Spring Boot. #DataJpaTest H2 embedded database create schema

I have couple of entities in my data layer stored in particular schema. For example:
#Entity
#Table(name = "FOO", schema = "DUMMY")
public class Foo {}
I'm trying to setup H2 embedded database for integration testing of my data layer.
I'm using #DataJpaTest annotation for my tests to get H2 embedded database configured automatically. However, the creation of tables fails because schema DUMMY is not created at DB initialization.
Any ideas on how to create schema before creation of tables in test cases?
I've tried to use #Sql(statements="CREATE SCHEMA IF NOT EXISTS DUMMY") but didn't succeed.
Also, I've tried to set spring.datasource.url = jdbc:h2:mem:test;INIT=CREATE SCHEMA IF NOT EXISTS DUMMY in my test.properties file together with TestPropertySource("classpath:test.properties"), but that didn't work too.
I had the same issue, I managed to resolve by creating schema.sql (in resources folder) with the content
CREATE SCHEMA IF NOT EXISTS <yourschema>
Documentation can be found here but imho the lack of real examples make it very complex.
Warning: this script is also executed within the normal (not test) environment.
Not mandatory, but good practice, add h2 dependency only in test scope
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
I think you are looking for this annotation:
#AutoConfigureTestDatabase(replace=Replace.NONE)
example:
#DataJpaTest
#AutoConfigureTestDatabase(replace= AutoConfigureTestDatabase.Replace.NONE)
class UserRepoTest {...}
After couple hours of struggling I've found a workaround.
You can define spring.jpa.properties.hibernate.default_schema = DUMMY in your application.properties.
And then set spring.jpa.properties.hibernate.default_schema = in your test.properties and use together with #TestPropertySource("classpath:test.properties")
So, in this way the schema DUMMY won't be created and the entities will be created in default schema.
In my case schema.sql under test/resources din't worked.
The following configuration in test/resources/application.yml file worked.
spring:
datasource:
username: sa
password: sa
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:usrmgmt;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;MODE=MYSQL;INIT=CREATE SCHEMA IF NOT EXISTS DUMMY;
liquibase:
change-log: classpath:db/changelog/db.changelog-master.xml
In the above configuration, provided the below additional configuration
INIT=CREATE SCHEMA IF NOT EXISTS DUMMY extension to the existing DB url. In the absence of this, faced the exception Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Schema "DUMMY" not found;.
spring.liquibase.change-log property. In the absence of this, faced the exception Caused by: liquibase.exception.ChangeLogParseException: classpath:/db/changelog/db.changelog-master.yaml does not exist.

Set default schema = SOMETHING in oracle using Spring Boot and Spring JDBC

I am working now with oracle and spring jdbc but I don't want to use the schema in my sql statements:
Example: Select * from SCHEMA.table
Is there any way to set default schema in application.properties or application.yml?
Assuming you define your database connections using spring datasources, you can set the default schema when defining the datasource configuration:
spring.datasource.schema = #value for your default schema to use in database
You can find more info here: Spring Boot Reference Guide. Appendix A. Common application properties
After doing some research, looks like Oracle driver doesn't let you set a default schema to work with, as noted here:
Default Schema in Oracle Connection URL
From that post, you have two options:
Execute this statement before executing your statements:
ALTER SESSION SET CURRENT_SCHEMA=yourSchema
Create synonyms for your tables/views/etc (which I find really cumbersome if we're talking about lots of elements in your database).
I would advice using the first option. From what I see, Spring boot doesn't offer a simple way to execute a statement when retrieving the connection, so the best bet will be to use an aspect around the getConnection method (or the method that retrieves the connection from the data source) and execute the statement there.
From your comment, an easier way to solve it is by using a script in spring.datasource.schema:
spring.datasource.schema = schema.sql
And then a file squema.sql with the following:
ALTER SESSION SET CURRENT_SCHEMA=mySchema
In spring boot, I've found another way of doing it,
#Bean
#ConfigurationProperties(prefix="spring.datasource")
public DataSource dataSource(#Value("${spring.datasource.schema}") String schema) {
DataSource datasource = DataSourceBuilder.create().build();
if(!schema.isEmpty() && datasource instanceof org.apache.tomcat.jdbc.pool.DataSource){
((org.apache.tomcat.jdbc.pool.DataSource) datasource).setInitSQL("ALTER SESSION SET CURRENT_SCHEMA=" + schema);
}
return datasource;
}
I found another way to get around this by updating entity class with
#Table(schema = "SCHEMA_NAME" ,name = "TABLE_NAME")
If you are using hikari, use spring.datasource.hikari.schema=YOUR_SCHEMA.
Works for me with SpringBoot + tomcat using Oracle.
I was having issues with the currently accepted answer; specifically, the schema would only be changed from the initial connection. If your app uses a connection pool, you need to configure the pool to apply SQL for each connection.
For instance, using the default jdbc pool in Spring Boot 1.5.x (Tomcat):
spring.datasource.tomcat.init-s-q-l = ALTER SESSION SET CURRENT_SCHEMA=mySchema
Connecting to the database as your user, you can create a trigger that will change the schema each time you login:
CREATE OR REPLACE TRIGGER LOGON_TRG
AFTER LOGON ON SCHEMA
BEGIN
EXECUTE IMMEDIATE 'ALTER SESSION SET CURRENT_SCHEMA = foo';
EXCEPTION
when others
then null;
END;
/
Another option is to create a datasource wrapper. Create the datasource as normal and then create the wrapper that forwards all methods except for the getConnection methods. For those I just added SQL to set the schema. We have multiple datasources and this allowed us to specify a different schema for each datasource. If anyone knows if there's an issue with this I'd love comments. Or if there's an alternative that uses the properties.

Resources