Hikari with Postgress datasource - spring-boot

What is the correct way to define hikari datasource in spring boot application ?
We are using this which works but I am not sure what PG datasource is used
datasource.test.jdbcUrl=url
datasource.test.username=username
datasource.test.password=pass
datasource.test.driver-class-name=org.postgresql.Driver
datasource.test.connection-test-query=SELECT 1
datasource.test.maximum-pool-size=5
with
HikariConfig config = new HikariConfig(props);
HikariDataSource ds = new HikariDataSource(config);
according to hikari README they are using ds with properties:
Properties props = new Properties();
props.setProperty("dataSourceClassName", "org.postgresql.ds.PGSimpleDataSource");
props.setProperty("dataSource.user", "test");
props.setProperty("dataSource.password", "test");
props.setProperty("dataSource.databaseName", "mydb");
...
where is defined PG datasource.
Is there any different between this two definition or I should used second one which is in Hikari wiki ? First one also use PGSimpleDataSource ?

Related

How to set configuration using application.properties in Hibernate?

I am new to Spring boot development.
What I did?
I tested the sample MySQL integration with Spring boot and tested it works fine.
What I am trying?
I am trying to use Hibernate APIs with my existing project. So I create a util class for creating Hibernate sessionFactory.
My code:
public static void initSessionFactory() {
System.out.print("initSessionFactory");
if (sessionFactory == null) {
try {
Configuration configuration = new Configuration();
//***** I don't want configuration here. ******
// Hibernate settings equivalent to hibernate.cfg.xml's properties
//Properties settings = new Properties();
// settings.put(Environment.DRIVER, "com.mysql.cj.jdbc.Driver");
// settings.put(Environment.URL, "jdbc:mysql://localhost:3306/hibernate_db?useSSL=false");
// settings.put(Environment.USER, "root");
// settings.put(Environment.PASS, "root");
// settings.put(Environment.DIALECT, "org.hibernate.dialect.MySQL5Dialect");
// settings.put(Environment.CURRENT_SESSION_CONTEXT_CLASS, "thread");
// settings.put(Environment.HBM2DDL_AUTO, "create-drop");
// settings.put(Environment.SHOW_SQL, "true");
// configuration.setProperties(settings);
//configuration.addAnnotatedClass(Student.class);
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties()).build();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
session = sessionFactory.openSession();
} catch (Exception e) {
e.printStackTrace();
}
}
}
My application.properties:(It works fine for without Hibernate)
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://localhost:3306/tcc
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.show-sql=true
My problem:
I already configured the jdbc environment & other configuration in my application.properties. It works fine. So I don't want to repeat the same configuration in my Java code. So I commented this configuration.
But without Java configuration it throws "The application must supply JDBC connections" error.
My Question:
How to set configuration from application.properties for Hibernate?
When you set the properties below in your app.properties, the Spring Boot will already make your DB connection ready when the application start.
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/db_example
spring.datasource.username=springuser
spring.datasource.password=ThePassword
spring.datasource.driver-class-name =com.mysql.jdbc.Driver
You do not need to create SessionFactory , ServiceRegistery etc. even if you do not want to manage DB connection manually.
This link also explain the steps in more detail. You will see that there is no any custom bean, factory or registerer to establish DB connection. Please see it.
https://spring.io/guides/gs/accessing-data-mysql/

spring jpa property spring.jpa.hibernate.ddl-auto not working for custom DB configuration in spring boot

in spring boot project, using custom DB configuration. One method is there where adding all properties in map. SQL Server DB
protected Map<String, Object> jpaProperties() {
HashMap<String, Object> jpaProperties = new HashMap<>();
jpaProperties.put("hibernate.ddl-auto", "validate");
jpaProperties.put("spring.jpa.hibernate.ddl-auto", "validate");
jpaProperties.put("hibernate.dialect", "org.hibernate.dialect.SQLServer2012Dialect");
jpaProperties.put("org.hibernate.envers.store_data_at_delete", "false");
return jpaProperties;
}
envers & those properties are working
"spring.jpa.properties.org.hibernate.envers.store_data_at_delete" for this adding "org.hibernate.envers.store_data_at_delete"
but, when adding "hibernate.ddl-auto", it is not validating schema.
Tried both "hibernate.ddl-auto" & "spring.jpa.hibernate.ddl-auto".
Read some stack overflow questions, saw most are telling to add "hibernate.hbm2ddl.auto", that is giving validating error, but for proper table also it is giving error
Tried adding "spring.jpa.generate-ddl" with value "true" too.
that means properties are getting used for custom db, only the ddl-auto one is not working.
Anything wrong in this?

Include newly added data sources into route Data Source object without restarting the application server

Implemented Spring's AbstractRoutingDatasource by dynamically determining the actual DataSource based on the current context.
Refered this article : https://www.baeldung.com/spring-abstract-routing-data-source.
Here on spring boot application start up . Created a map of contexts to datasource objects to configure our AbstractRoutingDataSource. All these client context details are fetched from a database table.
#Bean
#DependsOn("dataSource")
#Primary
public DataSource routeDataSource() {
RoutingDataSource routeDataSource = new RoutingDataSource();
DataSource defaultDataSource = (DataSource) applicationContext.getBean("dataSource");
List<EstCredentials> credentials = LocalDataSourcesDetailsLoader.getAllCredentails(defaultDataSource); // fetching from database table
localDataSourceRegistrationBean.registerDataSourceBeans(estCredentials);
routeDataSource.setDefaultTargetDataSource(defaultDataSource);
Map<Object, Object> targetDataSources = new HashMap<>();
for (Credentials credential : credentials) {
targetDataSources.put(credential.getEstCode().toString(),
(DataSource) applicationContext.getBean(credential.getEstCode().toString()));
}
routeDataSource.setTargetDataSources(targetDataSources);
return routeDataSource;
}
The problem is if i add a new client details, I cannot get that in routeDataSource. Obvious reason is that these values are set on start up.
How can I achieve to add new client context and I had to re intialize the routeDataSource object.
Planning to write a service to get all the client context newly added and reset the routeDataSource object, no need to restart the server each time any changes in the client details.
A simple solution to this situation is adding #RefreshScope to the bean definition:
#Bean
#Primary
#RefreshScope
public DataSource routeDataSource() {
RoutingDataSource routeDataSource = new RoutingDataSource();
DataSource defaultDataSource = (DataSource) applicationContext.getBean("dataSource");
List<EstCredentials> credentials = LocalDataSourcesDetailsLoader.getAllCredentails(defaultDataSource); // fetching from database table
localDataSourceRegistrationBean.registerDataSourceBeans(estCredentials);
routeDataSource.setDefaultTargetDataSource(defaultDataSource);
Map<Object, Object> targetDataSources = new HashMap<>();
for (Credentials credential : credentials) {
targetDataSources.put(credential.getEstCode().toString(),
(DataSource) applicationContext.getBean(credential.getEstCode().toString()));
}
routeDataSource.setTargetDataSources(targetDataSources);
return routeDataSource;
}
Add Spring Boot Actuator as a dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
Then trigger the refresh endpoint POST to /actuator/refresh to update the DataSource (actually every refresh scoped bean).
So this will depend on how much you know about the datasources to be added, but you could set this up as a multi-tenant project. Another example of creating new datasources:
#Autowired private Map <String, Datasource> mars2DataSources;
public void addDataSourceAtRuntime() {
DataSourceBuilder dataSourcebuilder = DataSourcebuilder.create(
MultiTenantJPAConfiguration.class.getclassloader())
.driverclassName("org.postgresql.Driver")
.username("postgres")
.password("postgres")
.url("Jdbc: postgresql://localhost:5412/somedb");
mars2DataSources("tenantX", datasourcebuilder.build())
}
Given that you are using Oracle, you could also use its database change notification features.
Think of it as a listener in the JDBC driver that gets notified whenever something changes in your database table. So upon receiving a change, you could reinitialize/add datasources.
You can find a tutorial of how to do this here: https://docs.oracle.com/cd/E11882_01/java.112/e16548/dbchgnf.htm#JJDBC28820
Though, depending on your organization database notifications need some extra firewall settings for the communication to work.
Advantage: You do not need to manually call the REST Endpoint if something changes, (though Marcos Barberios answer is perfectly valid!)

Set hikari pool size for custom DataSource

I want to change Hikari pool size for my custom DataSource, I use Spring boot 2+ version.
I can set dataSource url,dataSource password etc.
I wrote values to application.properties file.After that I read these values with environment.getproperty and set dataSource but I donot know same process for pool size:(
I am assuming you custom your dataSource by set your DataSource bean. then you can create custom hikariconfig as follow, remember to replace hard code values below with values in your environment.getproperty:
#Bean
public DataSource getDataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://yourhostname:port/dbname");
config.setDriverClassName("com.mysql.jdbc.Driver");
config.setUsername("dbUsername");
config.setPassword("dbPassword");
config.setMinimumIdle(10);
config.setMaximumPoolSize(10);
config.setConnectionTimeout(1500);
//you can set more config here
return new HikariDataSource(config);
}
Hikari prefix is spring.datasource.hikari.
You can set maximum pool size as 10:
spring.datasource.hikari.maximumPoolSize=10
spring.datasource.hikari.*= # Hikari specific settings
It will automatically set your pool size

Spring Boot with DB2 HADR ACR config

Is there a solution that is configured driver properties in the application.properties file?
DB2 HADR using clientRerouteAlternateServerName, clientRerouteAlternatePortNumber, enableClientAffinitiesList to indicate alternate server info.
I tried use below code to config datasource.
```
#Bean
public DataSource initds(){
Properties p = new Properties();
p.setProperty("user", "user");
p.setProperty("password", "password");
p.setProperty("clientRerouteAlternateServerName", "172.30.1.60,172.30.1.61");
p.setProperty("clientRerouteAlternatePortNumber", "53000,53000");
p.setProperty("enableClientAffinitiesList", "1");
DriverManagerDataSource dmds = new DriverManagerDataSource();
dmds.setDriverClassName("com.ibm.db2.jcc.DB2Driver");
dmds.setConnectionProperties(p);
dmds.setUrl("jdbc:db2://172.30.1.60:53000/dbsam");
return dmds;
}
```

Resources