Recently worked on migrating code to Spring Boot 2.x and am running into an issue configuring the datasource bean. We have two datasources and so we are building the DataSource beans by hand using a DataSourceBuilder.
Per the documentation , I am setting these properties:
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.username=sa
spring.datasource.password=
However, when I do that I get the following error:
java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName.
at com.zaxxer.hikari.HikariConfig.validate(HikariConfig.java:1059) ~[HikariCP-2.7.9.jar:na]
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:109) ~[HikariCP-2.7.9.jar:na]
If I change my settings to do this:
spring.datasource.jdbcUrl=jdbc:mysql://localhost/test
then it works.
It also works for a single datasource if I comment out the bean that creates the datasource explicitly which leads me to believe there's a problem in the datasourcebuilder code.
An example repository with just a single data source showing the issue is available here: https://github.com/azizabah/hikari-issue
So what changed between SB 1.5.X and SB 2.X from a configuration stand point when having multiple data sources?
You are missing the configuration of DataSourceProperties and directly trying to wire it.
You need to follow the following documentation to achieve what you want to do in first place :
https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-two-datasources
Co-incidentally somebody did same mistake and raised as bug in git, if you want you can see the same documentation getting referred as solution:
https://github.com/spring-projects/spring-boot/issues/12758
Related
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?
I'm using Spring Boot 2.0.3 release. I want to increase the maximum pool size of HikariCP which is 10 by default.
I tried changing it in applicaiton.properties with
spring.datasource.hikari.maximum-pool-size=200
but it is not working because in the logs it still show that max pool size is 10.
The reason I want to change is because I am somehow reaching that limit in staging and I have no idea what's causing it.
I faced similar issue recently (Spring Boot v2.1.3). Posting it here in case people bump into the same scenario.
Long story short: if you're initializing DataSource using #ConfigurationProperties, those properties don't seem to require hikari prefix for maximum-pool-size, unless I'm missing something. So spring.datasource.maximum-pool-size should work if you use #ConfigurationProperties(prefix = "spring.datasource").
Details: In my case I'm initializing DataSource myself using org.springframework.boot.jdbc.DataSourceBuilder, so that I could later use it in org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean:
#Bean
#Primary
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource primaryDataSource()
{
return DataSourceBuilder.create().build();
}
In this case property spring.datasource.hikari.maximum-pool-size taken from Common App Properties section in Spring Boot doc did not help. Neither did suggested above maximumPoolSize.
So I went and debugged Spring Boot code which lead me to org.springframework.boot.context.properties.bind.JavaBeanBinder and it's method bind. Value for property name for HikariDataSource setter setMaximumPoolSize was "maximum-pool-size", so just for sake of testing I renamed my property to be spring.datasource.maximum-pool-size and it finally worked.
Hope it helps. Please let me know in the comments if I missed something or took wrong path. Thanks!
As per HikariCP Github README it's maximumPoolSize so try using:
spring.datasource.hikari.maximumPoolSize = 200
But this will work only if you allow Spring Boot to create the DataSource. If you create the DataSource yourself Spring Boot properties have no effect.
Do note that 200 is a very high value that may negatively impact your database as each physical connection requires server resources. In most cases a lower value will yield better performance, see HikariCP wiki: About Pool Sizing.
Can I dynamically refresh properties that are used by Spring Boot's auto configuration setup?
For example, I have the following properties set (via cloud config) to auto configure a dataSource:
spring.datasource.username=user1
spring.datasource.password=test
Now if I change the password prop on the config server, and hit the /refresh endpoint, I can see that the updated prop is retrieved but the DataSource is not refreshed.
I know I can manually configure the DataSource beans and make sure they fall under a RefreshScope, but I was hoping to find a way to mark the auto configured properties as "refreshable". I have some use cases where I'd want to refresh props used by Spring Boot for other beans besides DataSources, and setting up some of those beans manually could be a pain.
I think I spoke too soon, at least as far as my DataSource example goes. A new db connection was being created with the updated props.
Which makes sense especially when looking at the docs here
This didn't re-connect some of my spring.cloud.stream.bindings properties I had, but in that case I can probably solve the issue with #RefreshScope.
There's a configuration property to set in case of the Autoconfigured bean is immutable (don't change the properties after initialized)
You can put a list (set) of classes that you need to be refreshed and you don't have control over the source code, you can put them under the property: spring.cloud.refresh.extra-refreshable
e.g.:
spring
cloud
refresh
extra-refreshable:
- org.springframework.mail.javamail.JavaMailSenderImpl
see: https://cloud.spring.io/spring-cloud-static/Greenwich.SR1/single/spring-cloud.html#refresh-scope
I started a new spring-boot 1.5.3 project. Added some starters:
data-jpa
starter-web
data-rest
And then added
devtools
h2
I can see the datasource is automatically set to jdbc:h2:mem:testdb. Everything is working fine but just out of curiosity I tried to determine from where the jdbc:h2:mem:testdb value comes from. I searched spring-boot, spring-data, spring jdbc and devtools projects' source code but I was unable to find out. As far as I can tell, the value does not come as default suggestion from h2 either.
So where does this value exactly come from?
That would be coming from this class, which also contains the defaults for other flavours of in-mem DBs.
https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/jdbc/EmbeddedDatabaseConnection.java
H2(EmbeddedDatabaseType.H2, "org.h2.Driver", "jdbc:h2:mem:%s;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"),
Which get's loaded via, the DataSourceAutoConfiguration if it meets the criteria,
https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceAutoConfiguration.java
The default for the database name, testdb, comes from a default set in the Datasourceproperties,
https://github.com/spring-projects/spring-boot/blob/master/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceProperties.java
private String name = "testdb";
The question is " Not able to set spring.datasource.type " ,
In spring boot 1.3 can work , but in spring boot 1.4 can't work , I don't know why ?
The following is my application.properties:
spring.datasource.type= com.alibaba.druid.pool.DruidDataSource
spring.datasource.url = jdbc:mysql://localhost:3306/api-2016
spring.datasource.username = root
spring.datasource.password = root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.max-active=20
spring.datasource.max-idle=8
spring.datasource.min-idle=8
spring.datasource.initial-size=10
Can anyone tell me why ?
As of Spring Boot 1.4, we no longer map the DataSource instance to spring.datasource so all the customizations (max-active, etc) aren't applied.
Please read the release notes. The customizations on DruidDataSource were never supported and this was working as a side effect. You can restore that behaviour by creating your own datasource bean:
#Bean
#ConfigurationProprties("app.datasource.druid")
public DataSource dataSource() { ... }
And change your druid-specific settings to app.datasource.druid. If you enable the annotation processor you'll get content assistance in your IDE for those keys!
Having said that and poking at the code, I realize now that we effectively broke spring.datasource.type so I've created #6695 to track that issue.