springboot quartz init schema only on first startup - spring-boot

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.

Related

How to set Spring profiles for deploying to Heroku

I have a Spring web app, with 3 different profiles for prod dev and test Each of these uses a different database, local for test and dev and a heroku postgres for prod.
I have set up my application.yaml file as below,
spring:
profiles:
active:
- dev
datasource:
url: jdbc:postgresql://ec2-35-168-65-132.compute-1.amazonaws.com:5432/*******
username: username
password: ******************
jpa:
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
jpa:
hibernate:
ddl-auto: update
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
format_sql: true
show-sql: true
javax:
persistence:
validation:
mode: none
show-sql: true
data:
web:
pageable:
default-page-size: 10
max-page-size: 100
---
spring:
config:
activate:
on-profile: prod
datasource:
url: jdbc:postgresql://ec2-35-168-65-132.compute-1.amazonaws.com:5432/********
username: username
password: **********
jpa:
hibernate:
ddl-auto: update
syftgolf:
upload-path: uploads-prod
---
spring:
config:
activate:
on-profile: dev
datasource:
url: jdbc:postgresql://localhost:5432/testdb
username: postgres
password: admin
jpa:
hibernate:
ddl-auto: create-drop
syftgolf:
upload-path: uploads-dev
---
spring:
config:
activate:
on-profile: test
datasource:
url: jdbc:postgresql://localhost:5432/syftgolf
username: postgres
password: admin
jpa:
hibernate:
ddl-auto: create-drop
syftgolf:
upload-path: uploads-test
I have slowly been updating this app over the months from a barebones project I did. I cant for the life of me, remember what this first part does.
spring:
profiles:
active:
- dev
datasource:
url: jdbc:postgresql://ec2-35-168-65-132.compute-1.amazonaws.com:5432/*********
username: username
password: *********
jpa:
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
jpa:
hibernate:
ddl-auto: update
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
format_sql: true
show-sql: true
javax:
persistence:
validation:
mode: none
show-sql: true
data:
web:
pageable:
default-page-size: 10
max-page-size: 100
I think spring:profiles:active: -dev sets the active profile to dev, so it should then use the database under dev? But I cant remember why the rest of the lines are placed here and not under a specific profile,
datasource:
url: jdbc:postgresql://ec2-35-168-65-132.compute-1.amazonaws.com:5432/***********
username: username
password: *************************
jpa:
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
jpa:
hibernate:
ddl-auto: update
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
format_sql: true
show-sql: true
javax:
persistence:
validation:
mode: none
show-sql: true
data:
web:
pageable:
default-page-size: 10
max-page-size: 100
if I remove this and just leave the active profile part, I get an error that the app cant start.
Please could someone help with the best way of laying out this application.yaml file and also is setting active profile in this file the correct way of doing it?
So if I am working on the app, i set this to dev do I then need to change it to prod before I push it to heroku using the heroku cli?
The best way would be to save an environment variable in your heroku application which will be using by your application to set the profile.
For example, this is a configuration for a simple spring boot thymeleaf application.
server:
port: ${PORT:4000}
spring:
application:
name: PROFILE-TEST
---
spring:
config:
activate:
on-profile: dev
custom:
message: "This is development environment"
---
spring:
config:
activate:
on-profile: prod
custom:
message: "This is production environment"
---
spring:
profiles:
active: ${PROFILE:dev}
Here I'm using spring.config.activate.on-profile to set an environment to have different custom.message.
By Default I'm setting the active profile with spring.profiles.active=${PROFILE:dev}. PROFILE is the environment variable we're gonna use to set different value during deployment. If there is no environment variable set for PROFILE, it'll default back to dev.
Now if I've written a controller which will only act on profile dev with the #Profile annotation like this
#Profile("dev")
#Controller
#RequestMapping("/")
#RequiredArgsConstructor
public class DevHomeController {
private final CustomConfigurationProperties customConfigurationProperties;
#GetMapping
public ModelAndView home(ModelAndView modelAndView) {
modelAndView.addObject("message", customConfigurationProperties.getMessage());
modelAndView.setViewName("dev-home.html");
return modelAndView;
}
}
It'll show something like
I've written another controller which will have a profile value #Profile("prod")
In the console type the below command to set an environment variable in heroku.
heroku config:set PROFILE=prod
And deploy the application. I'll look like
The message you see on the screen is coming from custom.message property you have set in your application.yml, and as we have set the environment variable for PROFILE, heroku is using that to set the running profile.

There is not connect another profile in Spring boot

I have a project with two properties.
application.yml (major)
spring:
config:
activate:
on-profile: local
application:
name: test-app
datasource:
cluster:
enabled: true
driverClassName: org.postgresql.Driver
hikari:
maximum-pool-size: 30
minimum-idle: 3
autoCommit: false
jpa:
database-platform: org.hibernate.dialect.PostgreSQL95Dialect
properties:
hibernate:
connection.provider_disables_autocommit: true
jdbc.lob.non_contextual_creation: true
open-in-view: false
application-local.yml
spring:
datasource:
read:
url: jdbc:postgresql://localhost:5432/test-app
write:
url:jdbc:postgresql://localhost:5432/test-app
username:
password:
driver-class-name: org.postgresql.Driver
jpa:
hibernate:
ddl-auto: update
properties:
open-in-view: false
I also have added the setting in IntelliJ IDEA
VM options also has used.
-Dspring.profiles.active=local
But during the launch I get an error:
Description:
Failed to configure a DataSource: 'url' attribute is not specified and
no embedded datasource could be configured.
Reason: Failed to determine suitable jdbc url
I assume that the specified profile did not start
Who has any ideas how to fix this ?

Spring Config profile file is not found

I've created this application-local.json into src/main/resources:
{
"spring": {
"datasource": {
"url": "jdbc:postgresql://xxx:yyy/db",
"username": "xxx",
"password": "xxx",
"driverClassName": "org.postgresql.Driver"
},
"profiles": {
"active": "local"
}
}
}
By other hand, apliication.yml:
spring:
jpa:
generate-ddl: false
show-sql: true
properties:
hibernate:
format_sql: true
jdbc:
lob:
non_contextual_creation: true
profiles:
active: local
management:
security:
enabled: false
endpoints:
web:
exposure:
include: '*'
---
spring:
profiles: local
server:
port: 8092
Currently, I'm getting this message:
***************************
APPLICATION FAILED TO START
***************************
Description:
Failed to auto-configure a DataSource: 'spring.datasource.url' is not specified and no embedded datasource could be auto-configured.
Reason: Failed to determine a suitable driver class
Action:
Consider the following:
If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).
When Spring application runs, it load properties from value of application.yml->spring->profiles->active. Spring supports only yml and .properties file as a source.
So, in your case Spring will look for application-local.yml or application-local.properties to read profile specific property.
But here, you have defined property file as a application-local.json and that a reason why spring is not reading values and you are getting exception.
Solution
Create application-local.yml or application-local.properties and paste your content and try. It should work.
Here is sample DB configuration.
spring.datasource.url=jdbc:mysql://localhost:3306/_schema name_
spring.datasource.username=_username_
spring.datasource.password=_password_
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
spring.jpa.show-sql = true
logging.level.org.hibernate.SQL=debug

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.

2 Hikari CPs with different datasource configurations?

Has anyone successfully configured two hikari connection pools with different datasources in a spring boot application? How do I do it using application.properties?
I know that this was asked a long time ago, but I think that it might help others.
In addition, I don't think that the "possible duplicates" mentioned above answer the question.
I'm using spring boot 2.0.4 with maven.
Instead of having a dedicated scope for hikary, as you would if you use one db, e.g.
datasource:
hikari:
connection-test-query: SELECT 1 FROM DUAL
minimum-idle: 1
maximum-pool-size: 2
pool-name: some-pool-name
You can take the settings that you want and put the directly inside the db scope, e.g.:
spring:
datasource:
db1:
type: com.zaxxer.hikari.HikariDataSource
maximum-pool-size: 2
minimum-idle: 1
pool-name: db1-pool
connection-test-query: SELECT 1 FROM DUAL
jdbc-url: jdbc:mysql://${host1}:${port1}/${db1}
username: ${db1-user}
password: ${db1-pass}
driver-class-name: com.mysql.cj.jdbc.Driver
db2:
type: com.zaxxer.hikari.HikariDataSource
maximum-pool-size: 2
minimum-idle: 1
pool-name: db2-pool
connection-test-query: SELECT 1 FROM DUAL
jdbc-url: jdbc:mysql://${host2}:${port2}/${db2}
username: ${db2-user}
password: ${db2-pass}
driver-class-name: com.mysql.cj.jdbc.Driver
As you can see the pool-name and size were set inside that scope.
Then in a java configuration file:
#Configuration
public class AppConfiguration {
....
#Bean("db1")
#ConfigurationProperties(prefix = "spring.datasource.db1")
public DataSource firstDataSource() {
return DataSourceBuilder.create().build();
}
#Bean("db2")
#ConfigurationProperties(prefix = "spring.datasource.db1")
public DataSource secondDataSource() {
return DataSourceBuilder.create().build();
}
}

Resources