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.
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
I'm working on application that get the DS from PCF (Pivotal Cloud FoundrY) User provided services. It's working properly but I want to understand how the validation interval is defined.
As Spring and PCF are managing my connection pool. I'd like to understand how that works.
public DataSource getProfileDS() {
PoolConfig poolConfig = new PoolConfig(5, 10, 30000);
DataSourceConfig dsConfig = new DataSourceConfig(poolConfig, null);
return connectionFactory().dataSource("profileDS", dsConfig);
}
Also, is there any way to set up the validation interval by my own like we are used to do under the tomcat?
How spring cloud defines validation interval under the Pivotal Cloud Foundry?
Spring Cloud Config will define a validation query that is appropriate for your relational database.
Examples:
MySQL
Oracle
Postgres
As to the validation interval, it does not look like that's being configured. Instead, the DBCP-like pools use testOnBorrow, and Hikari is configured to use connectionTestQuery. When testing before obtaining a connection from the pool, setting the validation interval is unnecessary.
Also, is there any way to set up the validation interval by my own like we are used to do under the tomcat?
Not if you're going to use Spring Cloud Connectors, but you don't have to use Spring Cloud Connectors. There's a couple of other ways you can do this.
Spring Boot exposes VCAP_SERVICES as properties like vcap.services.<name>.credentials.username. You could use those to manually define a DataSource. See here.
You can use the new java-cfenv library, which is intended to complement Spring Boot better.
Hope that helps!
I'm using Spring Boot 2.1.2 release (mongodb-driver v 3.8.2) and developing web application that operates with mongodb. My application is compatible with mongodb 3.4 version (This version doesn't support transactions) and now I'm introducing transactional mechanism. I annotate my service method with transactional annotation
#Transactional
public void process(Object argument) {
...
...
...
}
and it works fine for mongodb v 4, everything works just excpected - failed transactions are rolledback.
But when I start my app with mongodb v 3.4 my app crashes with
Sessions are not supported by the MongoDB cluster to which this client is connected
exception.
The problem is that I want my app to support both cases: transactional and non-transactional with the same code (for both mongodb versions). So I wonder how can I do it? It seems like my application should create session only for specific version of mongo, i.e. this annotation should be processed only for this case.
How can I do it?
I have found a solution. Spring checks for existence of PlatformTransactionManager in current context before creating a transaction. So if this bean is not defined, then session wouldn't be opened for transaction. Thus I had used on condition bean for this purpose in my configuration class:
#Bean
#Autowired
#ConditionalOnExpression("'${mongo.transactions}'=='enabled'")
MongoTransactionManager mongoTransactionManager(MongoDbFactory dbFactory) {
return new MongoTransactionManager(dbFactory);
}
So MongoTransactionManager bean will be created only if mongo.transactions parameter is set to enabled.
Not sure if it works, but you could try to move the #EnableTransactionManagement annotation to a new configuration class, add the annotations #Configuration and #Profile("enableTransactions") to the configuration class, and run the application using the given profile when you need the transaction management to be auto-configured, for instance using:
mvn spring-boot:run -Dspring-boot.run.profiles=enableTransactions
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.