Spring Boot / JPA / H2 - Table not found - spring

My application uses an embedded H2 with the following configuration:
spring:
profiles:
active: dev
datasource:
# url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
url: jdbc:h2:./db/app_db;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;
username: user
password: pass
initialization-mode: always
jpa:
show-sql: true
hibernate:
ddl-auto: none
naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy
properties:
hibernate:
ddl-auto: none
dialect: org.hibernate.dialect.H2Dialect
The database is accessed using Spring Data in the simplest form, i.e.:
public interface AttributeRepository extends CrudRepository<Attribute, UUID> {
List<Attribute> findByLabel(String label);
}
For some reason, when under load, some of the REST requests seem to fail with a JDBC exception:
org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "ATTRIBUTE" not found; SQL statement:
select attribute0_.id as id1_0_0_, attribute0_.description as descript2_0_0_, attribute0_.label as label3_0_0_ from attribute attribute0_ where attribute0_.id=? [42102-200]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:453) ~[h2-1.4.200.jar!/:na]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:429) ~[h2-1.4.200.jar!/:na]
at org.h2.message.DbException.get(DbException.java:205) ~[h2-1.4.200.jar!/:na]
at org.h2.message.DbException.get(DbException.java:181) ~[h2-1.4.200.jar!/:na]
at org.h2.command.Parser.readTableOrView(Parser.java:7628) ~[h2-1.4.200.jar!/:na]
at org.h2.command.Parser.readTableFilter(Parser.java:1970) ~[h2-1.4.200.jar!/:na]
at org.h2.command.Parser.parseSelectFromPart(Parser.java:2827) ~[h2-1.4.200.jar!/:na]
at org.h2.command.Parser.parseSelect(Parser.java:2959) ~[h2-1.4.200.jar!/:na]
at org.h2.command.Parser.parseQuerySub(Parser.java:2817) ~[h2-1.4.200.jar!/:na]
at org.h2.command.Parser.parseSelectUnion(Parser.java:2649) ~[h2-1.4.200.jar!/:na]
at org.h2.command.Parser.parseQuery(Parser.java:2620) ~[h2-1.4.200.jar!/:na]
at org.h2.command.Parser.parsePrepared(Parser.java:868) ~[h2-1.4.200.jar!/:na]
at org.h2.command.Parser.parse(Parser.java:843) ~[h2-1.4.200.jar!/:na]
at org.h2.command.Parser.parse(Parser.java:815) ~[h2-1.4.200.jar!/:na]
at org.h2.command.Parser.prepareCommand(Parser.java:738) ~[h2-1.4.200.jar!/:na]
at org.h2.engine.Session.prepareLocal(Session.java:657) ~[h2-1.4.200.jar!/:na]
The requests seem to fail arbitrarily, so while a request seems to fail, the next one works just fine, meaning the database is intact and schema initialised correctly.
Any suggestions?

Related

Function "IDENTITY" not found when inserting audited revision using Hibernate Envers (5.6.10) with Spring Boot 2.7 (H2 2.1.214, Hibernate-core 5.6.9)

When inserting an audited revision I get the following error:
Hibernate: insert into audited_revision (id, timestamp) values (default, ?)
2022-07-21 15:46:09.496 TRACE 67111 --- [ XNIO-1 task-1] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [TIMESTAMP] - [Thu Jul 21 15:46:09 CEST 2022]
Hibernate: call identity()
2022-07-21 15:46:09.504 WARN 67111 --- [ XNIO-1 task-1] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 90022, SQLState: 90022
2022-07-21 15:46:09.504 ERROR 67111 --- [ XNIO-1 task-1] o.h.engine.jdbc.spi.SqlExceptionHelper : Function "IDENTITY" not found; SQL statement:
call identity() [90022-214]
2022-07-21 15:46:09.518 ERROR 67111 --- [ XNIO-1 task-1] o.z.problem.spring.common.AdviceTraits : Internal Server Error
org.springframework.dao.InvalidDataAccessResourceUsageException: could not prepare statement; SQL [call identity()]; nested exception is org.hibernate.exception.SQLGrammarException: could not prepare statement
According to this issue on the Hibernate Jira it is supposed to be fixed in Hibernate core 5.6.5. https://hibernate.atlassian.net/browse/HHH-14985
I'm currently using Hibernate core 5.6.9 provided by Spring Boot 2.7.2 and I still get the above issue. The column is correctly created according to this piece of logging:
Hibernate: create table audited_revision (id bigint generated by default as identity, timestamp timestamp, primary key (id))
My relevant piece of application.yaml config:
spring:
jpa:
defer-datasource-initialization: true
database: H2
hibernate:
ddl-auto: create-drop
open-in-view: false
properties:
format_sql: true
org:
hibernate:
envers:
store_data_at_delete: true
hibernate:
temp:
use_jdbc_metadata_defaults: false
dialect: org.hibernate.dialect.H2Dialect
show-sql: true
Is this a bug in Hibernate or am I doing something wrong?
This issue is fixed in Hibernate core 5.6.13
https://hibernate.atlassian.net/browse/HHH-15561
Add MODE=LEGACY; in the database connection:
example application.yml:
spring:
datasource:
url: jdbc:h2:mem:test;MODE=LEGACY;
exemple application.properties:
spring.datasource.url=jdbc:h2:mem:test;MODE=LEGACY;

Hibernate JPA Spring Boot

I have created all the models for my spring boot application and successfully specified the relation between them as per business logic. In my properties file, I set the hibernate auto-ddl option as create to generate all the tables as per the relationship between the entities. I am also using liquibase for database migration.
The problem is that, from the logs I can see that hibernate is altering the table before creating it and therefore throwing the run time exception saying "Table not found". Why it is altering the table before creating it? How to solve this issue?
Any help would be highly appreciable. Thanks in advance.
Some logs example
Error executing DDL "alter table application drop foreign key FKrtuepaxepo3o6x0pkn0w62ucg" via JDBC Statement.
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "APPLICATION" not found; SQL statement:
alter table application drop foreign key FKrtuepaxepo3o6x0pkn0w62ucg
.......
.......
.......
Hibernate: drop table if exists application
create table application (id bigint not null auto_increment
alter table application add constraint UK_5jl5nuoh207t0japuutb4avd4 unique (application_name)
Why it is expecting table name as "APPLICATION" before creating "application"
#Table(name = "application")
#EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class Application extends AbstractAuditingEntity implements Serializable {
private static final long serialVersionUID = 1L;
}
I am using H2 database in the development and MYSQL in production. But, previously, I was using the "org.hibernate.dialect.MySQL5InnoDBDialect" dialect in "application-dev.yml". Changing it to h2 dialect(org.hibernate.dialect.H2Dialect) solved the problem.
But,what should be the proper dialect in application-prod.yml? I am using MYSQL in production. Current dialect I am using here is "org.hibernate.dialect.MySQL5InnoDBDialect". This will further create problem in production.
application-prod.yml
datasource:
# type: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/appscoredb
username:
password:
hikari:
poolName: Hikari
auto-commit: false
# h2:
# console:
# enabled: true
# settings:
# web-allow-others: true
jpa:
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
database: mysql
hibernate:
ddl-auto: none
show-sql: true
properties:
hibernate.id.new_generator_mappings: true
hibernate.connection.provider_disables_autocommit: true
hibernate.cache.use_second_level_cache: false
hibernate.cache.use_query_cache: false
hibernate.generate_statistics: false
liquibase:
# Remove 'faker' if you do not want the sample data to be loaded automatically
contexts: prod, faker
enabled: false
It is solved by using this dialect: org.hibernate.dialect.MySQL5Dialect
I hope it could help someone in near future.

Set hibernate dialect for jpa in YML

I tried to set hibernate dialect for jpa in YML,
checked many topics, but it does not set:
spring:
datasource:
hikari:
allow-pool-suspension: true
connection-timeout: 1000
name: testDb
jpa:
database: h2
generate-ddl: false
database-platform: h2
package-to-scan: com.x.model
properties:
hibernate:
dialect: com.x.data.core.hibernate.dialect.ExtendedH2Dialect
h2:
console:
enabled: true
path: /h2
How to fix this?
what is com.x.data.core.hibernate.dialect.ExtendedH2Dialect ? You have to use dialect as org.hibernate.dialect.H2Dialect
below is the sample
server:
port: 8096
spring:
datasource:
driverClassName: org.h2.Driver
url: jdbc:h2:~/test
username: sa
password:
h2:
console:
enabled: true
jpa:
hibernate.ddl-auto: update
generate-ddl: false
show-sql: false
properties:
hibernate:
dialect: org.hibernate.dialect.H2Dialect
Note:
I'm using spring-boot-starter-data-jpa 2.0.5

Spring Boot with in memory database fails

I'm trying to test my Spring Boot application with an embedded database h2. As for dev and prod, I will be using a MySQL database.
I would like to have different application.yml and schema.sql file for each mode.
The project structure is:
src
--main
----resources
------application.yml
------schema.sql
--test
----resources
------application-test.yml
------schema-test.sql
This is my RespositoryTest :
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
#DataJpaTest
public class IUserRepositoryTest {
#Autowired
private TestEntityManager entityManager;
#Autowired
private IUserRepository userRepository;
#Test
public void Should_ReturnEmployee_ForExistingEmail() {
User oneUser=new User("john","doe","example#email.com");
entityManager.persist(oneUser);
List<User> userList=userRepository.findUserByEmail("example#email.com");
assertThat(userList).isNotEmpty();
assertThat(userList.get(0)).isNotNull();
assertThat(userList.get(0).getEmail()).isEqualTo("example#email.com");
}
This is my test/resources/application-test.yml:
spring:
profiles: test
datasource:
url: jdbc:h2:mem:test;INIT=create schema IF NOT EXISTS mydb;DB_CLOSE_DELAY=-1
platform: h2
username: sa
password:
driverClassName: org.h2.Driver
jpa:
hibernate:
ddl-auto: create-drop
properties:
hibernate:
default-schema: mydb
dialect: org.hibernate.dialect.H2Dialect
This is my test/resources/schema-test.sql:
CREATE SCHEMA IF NOT EXISTS MYDB
As for my main/resources/application.yml:
logging:
level:
org.springframework.web: DEBUG
org:
hibernate:
SQL: DEBUG
spring:
jpa:
hibernate:
ddl-auto: update
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL5Dialect
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: toor
database:
driverClassName: com.mysql.jdbc.Driver
When I run my app as a spring boot one, the main application.yml is used and all is good, but when I run my tests, I get this error:
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL via JDBC Statement
Caused by: org.h2.jdbc.JdbcSQLException: Schema "MYDB" not found; SQL statement
Which causes all my tests to fail.
When I try to use this project structure:
src
--main
----resources
------application.yml
------schema.sql
--test
----resources
------application.yml
------schema.sql
The test succed but when I run my app as a spring boot, the test/resources/application.yml is the one being used instead of the main one.
Your tests are running with the "default" profile so it will only load the "default" configurations with no suffix (i.e. -test).
Try adding #ActiveProfiles("test") to your test class to enable the test profile.

org.h2.jdbc.JdbcSQLException: Schema "myschema" already exists

The issue is when I execute my integrations tests I get the exception :
Caused by: org.h2.jdbc.JdbcSQLException: Schema "myschema" already exists; SQL statement:
CREATE SCHEMA myschema [90078-196]
I have this application-test.yml :
debug: true
spring:
data:
jpa:
repositories:
enabled: true
jpa:
database: h2
generate-ddl: true
show-sql: true
hibernate:
ddl-auto: create-drop
properties:
hibernate.hbm2ddl.auto: create-drop
datasource:
url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=TRUE;DATABASE_TO_UPPER=false;INIT=CREATE SCHEMA IF NOT EXISTS myschema
username: sa
password:
driver-class-name: org.h2.Driver
What am I missing here ?
hbm2ddl is set as create-drop changing it to update would solve your issue.

Resources