Issue with DataSourceHealthIndicator in Spring Boot actuator - spring

Looking at the source code for DataSourceHealthIndicator if it fails to figure out database it will use default query "SELECT 1;" to health status of the datasource.
This query fails in my environment. How can I configure HealthCheckEndpoint to use DatasourceHealthIndicator with custom query.

You can define your own HealthIndicator with name dbHealthIndicator and it will be used instead of the default, something like
#Bean
public HealthIndicator dbHealthIndicator() {
DataSourceHealthIndicator indicator = new DataSourceHealthIndicator(dataSource());
indicator.setQuery("Your Query Here");
return indicator;
}
Note that you may want to share the database type and versions that you are using and which query fit so that this can be supported out-of-the-box. Boot already does for HSQL, Derby and Oracle plus all databases that support "SELECT 1"

There is an option to configure it without any java code.
DataSourceHealthContributorAutoConfiguration takes the validation query from DataSourcePoolMetadata.
E.g. for hikari, specify property spring.datasource.hikari.connection-test-query=select 1

Related

Spring boot native query and JPA Repository

I would like to share all my project Repository interfaces with different database implementation (PostgreSQL, MySQL, ...), but having also some specific Repository with native query, for every db platform.
How can I achieve it? Is it possible to annotate a Repository to be used only with a specific database?
if you can not do it with annotations you could find out the dialect of the database and act accordingly.
an example
private boolean isOracle() {
Session session = (Session) entityManager.getDelegate();
Dialect dialect = ((SessionFactoryImpl) session.getSessionFactory()).getJdbcServices().getDialect();
return dialect.getClass().getName().contains("Oracle");
}
so if (isOracle()) you would use your oracleJpaNativeRepository

How does springboot JPA knows which database will be used?

I got to know Java spring JPA a couple days ago and there is one question which really makes me confused.
As I create a repository and use 'save()' method to save some objects into it. How does it know what type of database I am using and which local location to save.
I know I can config database (h2) like:
spring.datasource.url=jdbc:h2:mem/mydb
Then JPA will know: ok you are using h2 database and url is "jdbc:h2:mem/mydb"
However, some people said this config is not mandatory. If without this config, how does JPA knows which database I gonna use?
From the spring-boot documentation:
You should at least specify the URL by setting the spring.datasource.url property. Otherwise, Spring Boot tries to auto-configure an embedded database.
The following class is responsible for providing default settings for embedded DB: org.springframework.boot.autoconfigure.jdbc.DataSourceProperties
public String determineDatabaseName() {
...
if (this.embeddedDatabaseConnection != EmbeddedDatabaseConnection.NONE) {
return "testdb";
}
...
}
This answer can also be helpful: Where does the default datasource url for h2 come from on Spring Boot?

Is it possible to have two embedded databases running in Spring Boot that are populated using spring.jpa.generate-ddl?

I have two databases that I connect to in my application.
I want to set up a dev-only profile that mocks these databases using an embedded H2 database, and I would like to have their schemas auto-created by using spring.jpa.generate-ddl=true. The entity classes for each database are in different java packages, which I hope might help me here.
Is such a thing possible using spring's autoconf mechanisms?
It is possible to use multiple databases in spring boot.
But spring boot can automatically configure only one database.
You need to configure the second database yourself.
#Bean
#ConfigurationProperties(prefix="second.datasource")
public DataSource secondDataSource(){
return DataSourceBuilder
.create()
.driverClassName("org.h2.Driver")
.build();
}
If you just need a jdbc connection, this would be already sufficient. As you want to use JPA you need also a second JPA configuration, that uses the second data source.
#Bean(name="secondEntityManager")
public LocalContainerEntityManagerFactoryBean mySqlEntityManagerFactory(EntityManagerFactoryBuilder builder,DataSource secondDataSource){
return builder.dataSource(secondDataSource)
.packages("com.second.entity")
.build();
}
You can find the code above and more in this post

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.

How to disable H2's DATABASE_TO_UPPER in Spring Boot, without explicit connection URL

I'm aware that H2 has a boolean property/setting called DATABASE_TO_UPPER, which you can set at least in the connection URL, as in: ;DATABASE_TO_UPPER=false
I’d like to set this to false, but in my Spring Boot app, I don’t explicitly have a H2 connection URL anywhere. Implicitly there sure is a connection URL though, as I can see in the logs:
o.s.j.d.e.EmbeddedDatabaseFactory: Shutting down embedded database:
url='jdbc:h2:mem:2fb4805b-f927-49b3-a786-2a2cac440f44;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false'
So the question is, what's the easiest way to tell H2 to disable DATABASE_TO_UPPER in this scenario? Can I do it in code when creating the H2 datasource with EmbeddedDatabaseBuilder (see below)? Or in application properties maybe?
This is how the H2 database is explicitly initialised in code:
#Configuration
#EnableTransactionManagement
public class DataSourceConfig {
#Bean
public DataSource devDataSource() {
return new EmbeddedDatabaseBuilder()
.generateUniqueName(true)
.setType(EmbeddedDatabaseType.H2)
.setScriptEncoding("UTF-8")
.ignoreFailedDrops(true)
.addScripts("db/init.sql", "db/schema.sql", "db/test_data.sql")
.build();
}
}
Also, I'm telling JPA/Hibernate not to auto-generate embedded database (without this there was an issue that two in-memory databases were launched):
spring.jpa.generate-ddl=false
spring.jpa.hibernate.ddl-auto=none
You can't w\ the generateUniqueName, but if you call setName("testdb;DATABASE_TO_UPPER=false") you can add parameters. I doubt this is officially supported, but it worked for me.
The spring code that generates the connection url is like this:
String.format("jdbc:h2:mem:%s;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false", databaseName)
You may want abandon using explicit creation via EmbeddedDatabaseBuilder. Spring Boot creates H2 instance automatically based on configuration. So I would try this in application.properties:
spring.datasource.url=jdbc:h2:file:~/testdb;DATABASE_TO_UPPER=false

Resources