I have a question about how to handle two different datasources in a Spring Boot application.
Use case:
I have one main repository (db) which must be connected all the time
(application scope), i have no problem with that, having
TransactionManager and EntityManager.
The second database connection should be only request scoped, with
dynamic credentials gathered from an httpRequest.
The datasources are both from PostgreSQL.
Is that even possible? If yes, what is the best way to achieve that.
Thanks for help.
This is an interesting twist on the two datasource pattern!
Your second datasource will have to be resolved based on information external to your application, so you won't be able to use the Spring application context.
You can configure a datasource programmatically in Spring, which is covered in this Q&A:
Configure DataSource programmatically in Spring Boot
Your case is slightly different since the credentials will be resolved at runtime, but can use the same idea.
Make sure you have the Spring JDBC dependency.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
Using a DataSourceBuilder, construct a new DataSource object using your credentials
public DataSource getDataSource(String user, String password) {
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.url(DBB_URL);
dataSourceBuilder.username(user);
dataSourceBuilder.password(password);
return dataSourceBuilder.build();
}
And then use that as the datasource for your code. You won't be able to Autowire it, so you'll have come up with a rational strategy for when to construct your datasource in your JDBC methods and use it with a Spring JdbcTemplate in a way that allows you the transaction integrity you are looking for.
There are other considerations that you haven't specified. This strategy assumes you are using the same JDBC driver for both data sources. If you are using different databases, you will have to add the dependencies for those libraries, and then specify the driver class for your dynamic datasource.
Related
We are documenting the technology stack of our applications. In one application, it connects to an Oracle database and uses Spring Boot 2.3.7 framework.
I need to definitively determine what connection pool technology it uses to connect to the Oracle database. Because Hikari comes with Spring Boot 2.x and the application is auto-configured, there are no references to Hikari.
How can I determine if Hikari is being used?
You could try to autowire the Datasource somewhere and then sys out the class name of the Datasource to see what implementation is being used.
#Autowired
private DataSource dataSource;
then in a method that will run after Spring initializes
System.out.println("DataSource : " + dataSource.getClass().toString());
A simple approach, reduce logging level of Hikari, it's quite verbose on DEBUG level and gives you information about configuration, number of connections and their statuses:
logging.level.com.zaxxer.hikari.HikariConfig=DEBUG
logging.level.com.zaxxer.hikari=DEBUG
I would like to use an H2 database in a Spring Boot application.
This is what I have in application.properties:
spring.datasource.name=testdb
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=whydoesthishavetobe
spring.datasource.password=sodifficult
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
This are the relevant lines in the build.gradle file:
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'com.h2database:h2'
When I check the connection for the H2 database, it's all good.
But despite this, when I POST new entities into the application, I see nothing getting created in the H2 database, and Hikari data source is getting used instead in the background, as I see from the logs.
Why is Spring ignoring the application.properties file and not using the H2 data source? How can I force it to use the H2 data source?
This is Spring Boot 2.3.4.RELEASE.
I guess you have multiple datasources and a datasource other tha H2 is being autowired as default.As Hirakicp is a connection pool not a db.
U need not get rid of Hirakicp rather set h2 datasources as primary
The below solution should work if you have multiple datasources ,
If you have multiple data source beans configured, it's just that spring is autowiring other data source to be used as a default source.
using #Primary annotation while declaring H2 Datasource bean should solve this.
Using this annotation will force spring to autowire the datult to h2 datasource.
in case you have not declared a datasource bean for H2 but have other datasource beans, you will need to declare the h2 bean and set it as primary using #primary annotation.
note - Hirakicp is a db connection object not a db .
Example -
#Bean("one")
public BasicDataSource dataSourceOne() {
BasicDataSource basicDataSource = new BasicDataSource();
basicDataSource.setUrl(env.getProperty("spring.a.connectionUrl"));
basicDataSource.setDriverClassName(env.getProperty("spring.a.DriverClass"));
basicDataSource.setUsername(env.getProperty("spring.a.username"));
basicDataSource.setPassword(env.getProperty("spring.a.password"));
// basicDataSource.setMaxActive(2);
return basicDataSource;
}
#Primary
#Bean("two")
public BasicDataSource dataSourceTwo() {
BasicDataSource basicDataSource = new BasicDataSource();
basicDataSource.setUrl(env.getProperty("spring.u.connectionUrl"));
basicDataSource.setDriverClassName(env.getProperty("spring.u.DriverClass"));
basicDataSource.setUsername(env.getProperty("spring.u.username"));
basicDataSource.setPassword(env.getProperty("spring.u.password"));
return basicDataSource;
}
I think this is happening because SpringBoot application creates its own in-memory embedded database while your database client creates its own in-memory embedded database.
I suggest you to change the database from in-memory to filesystem and see if the application and your database client shows the same data.
spring.datasource.url=jdbc:h2:file:/data/sample/testdb
You only need to change the database url to make it a file based database.
If you need to proceed with in-memory approach, you can connect to that via tcp so that both your application and client can use the same database.
spring.datasource.url=jdbc:h2:tcp://localhost/mem:testdb
What do you mean by Why is Spring ignoring the application.properties file and not using the H2 data source? Hikari is connection pool, not a datasource. If you would like to provide your own datasource, you have to inject a bean with the configuration of your interest.
Connection pool A connection pool is a cache of database connections maintained so that the connections can be reused when future requests to the database are required.
Datasource Is where data that is being used to run a report or gain information is originating from.
Check here for more on connection pools: https://www.baeldung.com/java-connection-pooling
But, if it the logging that you don't like, you can set the logger to error with org.zaxxer.hikari=error
In Spring boot application.properties file we have the following options:
server.tomcat.max-threads = 100
server.tomcat.max-connections = 100
spring.datasource.tomcat.max-active = 100
spring.datasource.tomcat.max-idle = 30
This is my repository class
public interface UserRepository extends JpaRepository<Users,Integer>{}
This is the service class
#Service
#Transactional(rollbackFor = Exception.class)
public class UserService {
#Autowired
private UserRepository userRepository;
public User getUserById(Integer id){return userRepository.findOne(id)}
The question is, how userRepository create the connection to DB and will it use the connection pool from my application properties file. I come from JDBC and hibernate where I used DataManager, DataSource, Connection classes to use the connection pool, but in spring boot I didn't have any line of code with this classes and everything work fine
It works as it worked before but with Spring Boot, Spring makes more tasks for you.
With or without Spring, DAO class as UserRepository doesn't manipulate directly the datasource and doesn't create directly the JDBC connections either.
These are manipulated by the EntityManagerFactory implementation you are using.
With Spring-Hibernate, you still had to configure the EntityManagerFactory.
Now with Spring Boot, you don't need to configure it.
It is done for you.
The new thing of Spring Boot is that you can also configure the server datasource properties now :
server.tomcat.max-threads = 100
server.tomcat.max-connections = 100
spring.datasource.tomcat.max-active = 100
spring.datasource.tomcat.max-idle = 30
as the Tomcat server can be started by the Spring Boot application itself.
This part of the Spring Boot documentation gives the preference order of the datasource implementation :
Production database connections can also be auto-configured using a
pooling DataSource. Here’s the algorithm for choosing a specific
implementation:
We prefer the Tomcat pooling DataSource for its performance and
concurrency, so if that is available we always choose it.
Otherwise, if HikariCP is available we will use it.
If neither the Tomcat pooling datasource nor HikariCP are available
and if Commons DBCP is available we will use it, but we don’t
recommend it in production and its support is deprecated.
Lastly, if Commons DBCP2 is available we will use it.
Update:
As per Spring Boot 2.x, HikariCP is the default connection pool mechanism.
In Spring Boot - is there anyway to only connect to the database when it is required the first time?
For example - lazy load the database setup?
I understand this is not the usual pattern but would interested in hearing if there is a solution to this
Thanks
Damien
n Spring Boot - is there anyway to only connect to the database when it is required the first time? For example - lazy load the database setup?
Spring Data and Hibernate can do that setup.
I wonder if you can use #Configuration and #Lazy at the same time, and the documentation suggests it is doable but it will create all the bean lazily.
Whereas, if you want to selectively create datasource bean lazily among other beans, then, in that case you need to that use #Lazy on datasource bean
#Configuration
#Lazy
public class YourDataSourceConfigClass {//datasource bean}
I use a lot of JDBC code in my Swing desktop application. Now I read about JDBCTemplate from Spring in Spring in Action and it looks like a nice API for working with JDBC.
But Spring JDBC seem to need some XML configuration files for beans. Is there any way I can use JDBCTemplate without these XML configuration files (e.g. with annotations)? Or how can I use this JdbcTemplate in a Swing desktop application for database access?
You can have a Spring Context without XML by creating a #Configuration anotated java class and create the Spring Context using the AnnotationConfigApplicationContext class to load the config
see Spring JavaConfig for a code sample.
While using Spring as the backbone of your application certainly has merit, and indeed annotation-based configuration can free you from 'XML hell', if you just want to use JdbcTemplate 'raw' there's nothing preventing you from doing so.
Just make sure you supply it with a valid DataSource, such as PGPoolingDataSource for example, if you're using PostgreSQL. If your JDBC vendor does not provide a DataSource implementation, then feel free to use Spring's SimpleDriverDataSource.
For example:
DataSource ds = new SimpleDriverDataSource(LegacyDriver.class,
"jdbc:legacy://database", "username", "password");
JdbcTemplate jdbc = new JdbcTemplate(ds);
// Use jdbc to do stuff
Even though its technically possible - it would defeat the purpose and design of Spring based application.
My suggestion would be to start using Spring framework as a backbone for you application. I promise you that your application will only benefit from using it (better design, clear separation of concerns, better testability etc ). Setting up JbdcTemplate using Spring context is almost trivial.
You already reading 'Spring in Action' - just start using it :)
Take a look at Spring Reference Documentation - the best Spring resource, period