Spring Boot with in memory database fails - spring

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.

Related

springboot quartz init schema only on first startup

This is my config:
#Bean
#QuartzDataSource
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource quartzDataSource() {
return DataSourceBuilder.create().build();
}
and this is my app.yml:
datasource:
url: my-url
jdbcUrl: ${spring.datasource.url}
username: 'root'
password: 'root'
...
quartz:
job-store-type: jdbc
jdbc:
initialize-schema: always
wait-for-jobs-to-complete-on-shutdown: true
properties:
org:
quartz:
dataSource:
quartz-data-source:
provider: hikaricp
driver: com.mysql.cj.jdbc.Driver
URL: ${spring.datasource.url}
user: ${spring.datasource.username}
password: ${spring.datasource.password}
maximumPoolSize: 5
connectionTestQuery: SELECT 1
validationTimeout: 5000
idleTimeout: 1
scheduler:
instanceId: AUTO
instanceName: my-project-scheduler
jobStore:
class: org.quartz.impl.jdbcjobstore.JobStoreTX
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
useProperties: false
misfireThreshold: 60000
clusterCheckinInterval: 30000
isClustered: true
dataSource: quartz-data-source
threadPool:
class: org.quartz.simpl.SimpleThreadPool
threadCount: 1
threadPriority: 5
threadsInheritContextClassLoaderOfInitializingThread: true
My question:
If I set initialize-schema: always then the qrtz tables are created on each application startup.
On the other side, if I set initialize-schema: never then I get an error on the first startup that the qrt tables are missing.
Is there a way to configure it to initialize the qrtz tables only if they do not exist?
You are gonna need a migration tool to handle the database creation.
Spring Boot provides two options: Flyway and LiquidBase.
Choose one, create migration scripts and you are up and running.
I personally like the Flyway approach.
You just add implementation 'org.flywaydb:flyway-core' to your build.gradle file (or the maven alternative).
Then add this to your application.yml
spring:
flyway:
enabled: true
baseline-on-migrate: true
Then create db/migration folder in resources folder and put in your migration scripts eg. V1_0_0__db_init.sql (flyway has its own naming convention).
To get the create SQL scripts I recommend that you export them from running database.
Also do not forget to change the spring.jpa.hibernate.ddl-auto to validate.

Why does 'ConversionException' occur in 'TrackingEventProcessor' of Axon framework?

with Axon 4.5
with Spring Boot 2.5.2
with Spring JPA
I wrote Saga management as below
#Saga
class OrderSagaManagement {
#Autowired
private lateinit var eventGateway: EventGateway
#StartSaga
#SagaEventHandler(associationProperty = "orderId")
fun handle(orderCreatedEvent: OrderCreatedEvent) {
val paymentId = Random().nextInt(10000)
SagaLifecycle.associateWith("paymentId", paymentId)
eventGateway.publish(PaymentEvent(paymentId, orderCreatedEvent.orderId))
}
...
}
When I dispatch OrderCreateEvent, ConversionException occurs in TokenEventProcessor#processingLoop() as below.
application.yml is as below.
spring:
application:
name: order-service
datasource:
url: mysql
username: mysql
password:
driver-class-name: com.mysql.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
axon:
serializer:
general: xstream
axonserver:
servers: localhost:8124
bulid.gradle
implementation("org.axonframework:axon-spring-boot-starter:4.5")
Why does 'ConversionException' occur in 'TrackingEventProcessor' of Axon framework?

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.

Configure Spring boot with H2 database and Liquibase

I am using Spring boot2, I am trying to configure a Unit Test using H2 + Liquibase + JUNIT.
I think that liquibase is not executing the changeLog files and apply the SQL Commands, the unit test does not recognized my tables.
I put wrongs sql in my file to see if the changelog files are executed, but, seems that is not being executing.
Why my application can not access table? Maybe liquibase is not executing?
in my src/test/resource I have this file: application.yml
spring:
application:
name: my-api
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:myDB;MODE=MySQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
username: sa
password: sags
liquibase:
enabled: true
user: sa
password: sags
change-log: classpath:/db/changelog/db.changelog-master.xml
jpa:
hibernate:
ddl-auto: none
database-platform: org.hibernate.dialect.H2Dialect
show-sql: true
properties:
hibernate:
use_sql_comments: true
format_sql: true
h2:
console:
enabled: true
path: /console
My Test class:
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringRunner.class)
#SpringBootTest
public class FooRepositoryTest {
#Autowired
private FooRepository fooRepository;
#Test
public void findAllMustReturnAnything() {
List<Object> result = fooRepository.tables();
}
}
The FooRepository method:
#Query(value = "SHOW TABLES", nativeQuery = true)
List<Object> tables();
When I run my Unit Test I have the follow result:
My changelog file is in : src/main/resources/db
UPDATE: I found why liquibase was not executing my sql codes. It was because my SQL files had "dbms:mysql", so, how I am executing with H2 liquibase will not apply.
-- changeset 1.0:2 dbms:mysql
command
-- rollback command
Now, I need to know why my selected database in the session is not myDB.
I think in you case Spring turns on auto configure datasource.(https://docs.spring.io/spring-boot/docs/1.5.9.RELEASE/api/org/springframework/boot/test/autoconfigure/orm/jpa/AutoConfigureTestDatabase.Replace.html)
Try to turn it off.
spring.test.database.replace=none
And there is some unnecessary configuration.
liquibase:
user: sa
password: sags
You can remove user&password, liquibase use it from datasource.

Error resolving template on deploy jar or war on spring boot

when i run my application on embedded tomcat server all thing is good.
but when i deploy jar or war on other server or container, server on some url give me error:
Error resolving template "/shop/index", template might not exist or might not be accessible by any of the configured Template Resolvers
this is my application.yml:
server:
port: 8080
logging:
level:
com.mousavi007.shop: debug
spring:
datasource:
url: jdbc:mysql://localhost:3306/shop2
username: *******
password: *******
platform: mysql
jpa:
hibernate:
ddl-auto: update
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
database: mysql
show-sql: true
thymeleaf:
mode: LEGACYHTML5
shop controller:
#Slf4j
#Controller
#RequestMapping("/shop")
public class ShopController {
#GetMapping({"","/"})
public String Shop(Model model, #RequestParam("pageSize") Optional<Integer> pageSize,
#RequestParam("page") Optional<Integer> page){
****
****
****
****
return "/shop/index";
}
}
change
return "/shop/index";
to
return "shop/index";

Resources