I'm working with Spring Boot/Spring Batch, and need to provide two jdbc Data Sources.
I can't find a way to automatically load the config parameters from my application.properties.
//BatchConfiguration which uses both Data Sources:
#Configuration
#EnableBatchProcessing
public class BatchConfiguration {
#Bean
public JdbcBatchItemWriter<Customer> writer(#Qualifier("dataSourceOne") DataSource dataSource) {
return new JdbcBatchItemWriterBuilder<Customer>()
.itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>())
.sql("..."))
.dataSource(dataSource)
.build();
}
#Bean
public JdbcCursorItemReader<Customer> reader(#Qualifier("dataSourceTwo") DataSource dataSource) {
return new JdbcCursorItemReaderBuilder<Customer>()
.dataSource(dataSource)
.name("myItemReader")
.sql("...")
.rowMapper(new CustomerRowMapper())
.build();
}
Above code works with the following Configuration, which has the DataSource provided directly:
//WORKING SOLUTION
#Configuration(proxyBeanMethods = false)
public class DataSourcesConfiguration {
#Bean("dataSourceOne")
#Primary
public DataSource dataSource() {
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.url("jdbc:h2:mem:AAA-h2");
dataSourceBuilder.username("AAA");
dataSourceBuilder.password("AAA");
dataSourceBuilder.driverClassName("org.h2.Driver");
return dataSourceBuilder.build();
}
#Bean("dataSourceTwo")
public DataSource dataSourceTwo() {
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.url("jdbc:oracle:thin:#AAA");
dataSourceBuilder.username("AAA");
dataSourceBuilder.password("AAA");
dataSourceBuilder.driverClassName("oracle.jdbc.driver.OracleDriver");
return dataSourceBuilder.build();
}
}
Now if I try to create the DataSource from my application properties via annotation #ConfigurationProperties, it will not work:
//NOT WORKING
#Configuration(proxyBeanMethods = false)
public class DataSourcesConfiguration {
#Bean("dataSourceOne")
#Primary
#ConfigurationProperties(prefix="data1.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Bean("dataSourceTwo")
#ConfigurationProperties(prefix="data2.datasource")
public DataSource dataSourceTwo() {
return DataSourceBuilder.create().build();
}
}
application.properties:
data1.datasource.url=jdbc:h2:mem:AAA-h2
data1.datasource.username=AAA
data1.datasource.password=AAA
data1.datasource.driverClassName=org.h2.Driver
data2.datasource.url=jdbc:oracle:thin:#AAA
data2.datasource.username=AAA
data2.datasource.password=AAA
data2.datasource.driverClassName=oracle.jdbc.driver.OracleDriver
I receive the error Unable to detect database type in the non working version.
How can I correctly configure and provide a DataSource through my properties in application.properties?
The values to use in creating a DataSource are actually part of another class DataSourceProperties
which you can also use to create a DataSource.
Following is a snippet from TaskDbConfig (this class also contains information if you need more functions).
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import com.zaxxer.hikari.HikariDataSource;
#Bean
#ConfigurationProperties("data1.datasource")
public DataSourceProperties data1DataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#ConfigurationProperties("data1.datasource.hikari")
public HikariDataSource data1DataSource() {
// Different types are documented at
// https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/jdbc/DataSourceBuilder.html
return data1DataSourceProperties().initializeDataSourceBuilder()
.type(HikariDataSource.class).build();
}
application.yml
data1.datasource.platform: h2
data1.datasource.url: 'jdbc:h2:mem:test'
# Hikari config properties: https://github.com/brettwooldridge/HikariCP#configuration-knobs-baby
data1.datasource.hikari.minimumIdle: 1
data1.datasource.hikari.maximumPoolSize: 4
Related
I want to develop an application to connect to multiple oracle databases and fetch data from same table from each database.
I have tried using the multiple datasource for every database and fetch the data from the tables.
Resource: https://medium.com/#joeclever/using-multiple-datasources-with-spring-boot-and-spring-data-6430b00c02e7
DB1 Config:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef = "CU1EntityManagerFactory", basePackages = {
"com.javatechie.multiple.ds.api.cu1.repository" })
public class CU1Config {
#Primary
#Bean(name = "CU1DataSource")
#ConfigurationProperties(prefix = "spring.cu1.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Primary
#Bean(name = "CU1EntityManagerFactory")
public LocalContainerEntityManagerFactoryBean CU1EntityManagerFactory(EntityManagerFactoryBuilder builder,
#Qualifier("CU1DataSource") DataSource dataSource) {
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto", "update");
properties.put("hibernate.dialect", "org.hibernate.dialect.Oracle12cDialect");
return builder.dataSource(dataSource).properties(properties)
.packages("com.javatechie.multiple.ds.api.model").persistenceUnit("Unit").build();
}
}
DB2 Config:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(entityManagerFactoryRef = "CU2EntityManagerFactory", basePackages = {
"com.javatechie.multiple.ds.api.cu2.repository" })
public class CU2Config {
#Bean(name = "CU2DataSource")
#ConfigurationProperties(prefix = "spring.cu2.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "CU2EntityManagerFactory")
public LocalContainerEntityManagerFactoryBean CU2EntityManagerFactory(EntityManagerFactoryBuilder builder,
#Qualifier("CU2DataSource") DataSource dataSource) {
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto", "update");
properties.put("hibernate.dialect", "org.hibernate.dialect.Oracle12cDialect");
return builder.dataSource(dataSource).properties(properties)
.packages("com.javatechie.multiple.ds.api.model").persistenceUnit("Unit").build();
}
}
But the issue that I am facing is for every datasource I have to create a separate config class and also a dedicated repository and service, which is code repeatability though the work from each DB is same to fetch data from a particular table.
And also in future if I want to add any new database I have to repeat the same above process again.
Any help regarding better approach for code reusability is highly appreciated.
You can do it directly through the properties file
spring.datasource.jdbcUrl = [url]
spring.datasource.username = [username]
spring.datasource.password = [password]
spring.second-datasource.jdbcUrl = [url]
spring.second-datasource.username = [username]
spring.second-datasource.password = [password]
Then you need to create the configurations for the datasources:
#Configuration
#PropertySource({"classpath:persistence-multiple-db-boot.properties"})
#EnableJpaRepositories(
basePackages = "com.baeldung.multipledb.dao.user",
entityManagerFactoryRef = "userEntityManager",
transactionManagerRef = "userTransactionManager")
public class PersistenceUserAutoConfiguration {
#Primary
#Bean
#ConfigurationProperties(prefix="spring.datasource")
public DataSource userDataSource() {
return DataSourceBuilder.create().build();
}
// userEntityManager bean
// userTransactionManager bean
}
The config for the second one:
#Configuration
#PropertySource({"classpath:persistence-multiple-db-boot.properties"})
#EnableJpaRepositories(
basePackages = "com.baeldung.multipledb.dao.product",
entityManagerFactoryRef = "productEntityManager",
transactionManagerRef = "productTransactionManager")
public class PersistenceProductAutoConfiguration {
#Bean
#ConfigurationProperties(prefix="spring.second-datasource")
public DataSource productDataSource() {
return DataSourceBuilder.create().build();
}
// productEntityManager bean
// productTransactionManager bean
}
You can find more about this implementation here
If you are going to create a serious service, you should know only how to config them, how to use them, and how to control transaction for all of databases via Spring.
You can see the runnable example and some explanation in https://github.com/surasint/surasint-examples/tree/master/spring-boot-jdbi/10_spring-boot-two-databases (see what you can try in README.txt)
I copied some code here.
First you have to set application.properties like this
#Database
database1.datasource.url=jdbc:mysql://localhost/testdb
database1.datasource.username=root
database1.datasource.password=root
database1.datasource.driver-class-name=com.mysql.jdbc.Driver
database2.datasource.url=jdbc:mysql://localhost/testdb2
database2.datasource.username=root
database2.datasource.password=root
database2.datasource.driver-class-name=com.mysql.jdbc.Driver
Then define them as providers (#Bean) like this:
#Bean(name = "datasource1")
#ConfigurationProperties("database1.datasource")
#Primary
public DataSource dataSource(){
return DataSourceBuilder.create().build();
}
#Bean(name = "datasource2")
#ConfigurationProperties("database2.datasource")
public DataSource dataSource2(){
return DataSourceBuilder.create().build();
}
Note that I have #Bean(name="datasource1") and #Bean(name="datasource2"), then you can use it when we need datasource as #Qualifier("datasource1") and #Qualifier("datasource2") , for example
#Qualifier("datasource1")
#Autowired
private DataSource dataSource;
If you do care about transaction, you have to define DataSourceTransactionManager for both of them, like this:
#Bean(name="tm1")
#Autowired
#Primary
DataSourceTransactionManager tm1(#Qualifier ("datasource1") DataSource datasource) {
DataSourceTransactionManager txm = new DataSourceTransactionManager(datasource);
return txm;
}
#Bean(name="tm2")
#Autowired
DataSourceTransactionManager tm2(#Qualifier ("datasource2") DataSource datasource) {
DataSourceTransactionManager txm = new DataSourceTransactionManager(datasource);
return txm;
}
Then you can use it like
#Transactional //this will use the first datasource because it is #primary
or
#Transactional("tm2")
The most important part, which you will hardly find an example in anywhere: if you want a method to commit/rollback transactions of both databases, you need ChainedTransactionManager for tm1 and tm2 , like this:
#Bean(name = "chainedTransactionManager")
public ChainedTransactionManager getChainedTransactionManager(#Qualifier ("tm1") DataSourceTransactionManager tm1, #Qualifier ("tm2") DataSourceTransactionManager tm2){
return new ChainedTransactionManager(tm1, tm2);
}
To use it, add this annotation in a method #Transactional(value="chainedTransactionManager") for example
#Transactional(value="chainedTransactionManager")
public void insertAll() {
UserBean test = new UserBean();
test.setUsername("username" + new Date().getTime());
userDao.insert(test);
userDao2.insert(test);
}
This should be enough. See example and detail in the link above.
I would like to connect my application with 2 different databases. This is what I have tried:
public class DataSourceWilaConfig {
#Bean
#Primary
#ConfigurationProperties(prefix="spring.wila")
public DataSource wila() {
return DataSourceBuilder.create().build();
}
}
public class DataSourceWaldConfig {
#Bean
#ConfigurationProperties(prefix = "spring.wald")
public DataSource wald() {
return DataSourceBuilder.create().build();
}
}
And so in application.properties I have added:
spring.datasource.url=
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.datasource.username=
spring.datasource.password=
spring.wald.datasource.url=
spring.wald.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.wald.datasource.username=
spring.wald.datasource.password=
But Intellij tells me: Cannot resolve configuration property 'spring.wald.datasource.url'
What am I doing wrong?
Instead of returning DataSource, you could return DataSourceProperties, like:
#Configuration
#EnableConfigurationProperties
public class DataSourceWaldConfig {
#Bean
#ConfigurationProperties(prefix = "spring.datasource.wald")
public DataSourceProperties dataSourceProperties() {
return new DataSourceProperties();
}
}
#Configuration
#EnableConfigurationProperties
public class DataSourceWilaConfig {
#Bean
#Primary
#ConfigurationProperties(prefix="spring.datasource.wila")
public DataSourceProperties wila() {
return new DataSourceProperties();
}
}
Also, the dependency spring-boot-configuration-processor will be required.
Important: After that's done, you should rebuild your project.
I wanted to declare two DataSource beans and use one of them dynamically using AbstractRoutingDataSource, which is declared as #Primary bean. Surprisingly, I was not able to run my application because of cyclic dependency:
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration
┌─────┐
| dataSource defined in <myclass>
↑ ↓
| readOnlyDataSource defined in <myclass>
↑ ↓
| org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerInvoker
└─────┘
It is cause because of this implementation:
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Bean
#Primary
DataSource dataSource(#Qualifier("firstDS") DataSource firstDS,
#Qualifier("secondDS") DataSource secondDS) {
MyRoutingDataSource ds = new MyRoutingDataSource();
ds.setCurrentDS(firstDS);
return ds;
}
#Bean("firstDS")
public DataSource firstDS(DataSourceProperties properties) {
return properties.initializeDataSourceBuilder().build();
}
#Bean("secondDS")
public DataSource secondDs(DataSourceProperties properties) {
return properties.initializeDataSourceBuilder().build();
}
class MyRoutingDataSource extends AbstractRoutingDataSource {
private DataSource currentDS;
public void setCurrentDS(DataSource currentDS) {
this.currentDS = currentDS;
}
#Override
protected Object determineCurrentLookupKey() {
return currentDS;
}
}
}
Please note that I don't want to exclude DataSourceAutoConfiguration - it provides some additional functionally that I want to use in my project (e.g. DataSourceInitializer).
Could you please explain to me why it does not work? I feel that this error message is misleading. There is no cyclic dependency between HibernateJpaConfiguration and DataSourceInitializerInvoker. Both of them uses DataSource which primary definition I provide.
There is full project with that issue: https://github.com/kozub/spring-dependency-management-bug
I ran into the same problem you have, with the difference that I am not using DataSourceAutoConfiguration.
I'm not a Spring expert, so I can't tell you the root cause. But I was able to get my code to work by going from something like this, which is similar to what you posted:
#Bean
#Primary
DataSource dataSource(#Qualifier("firstDS") DataSource firstDS,
#Qualifier("secondDS") DataSource secondDS) {
MyRoutingDataSource ds = new MyRoutingDataSource();
ds.setFirstDS(firstDS);
ds.setSecondDs(secondDS);
return ds;
}
#Bean("firstDS")
public DataSource firstDS() {
return /*create first DS*/
}
#Bean("secondDS")
public DataSource secondDs(DataSourceProperties properties) {
return /*create second DS*/
}
To this:
#Bean
DataSource dataSource() {
DataSource first = /*create first DS*/
DataSource second = /*create second DS*/
MyRoutingDataSource ds = new MyRoutingDataSource();
ds.setFirstDS(first);
ds.setSecondDs(second);
return ds;
}
As you can see, I was able to solve the problem by only having one Spring bean of type DataSource. I created the two "first" and "second" DataSources inside the method which creates the routing datasource so that they don't have to be Spring beans. Having only one bean of type DataSource got rid of my circular dependency error.
This solved my problem, but you also want to use DataSourceAutoConfiguration.
I think you may be able to achieve that with something like this:
#Bean
DataSource dataSource(#Qualifier("firstDSproperties") DataSourceProperties firstDSprops,
#Qualifier("secondDSproperties") DataSourceProperties secondDSprops) {
DataSource first = firstDSprops.initializeDataSourceBuilder().build();
DataSource second = secondDSprops.initializeDataSourceBuilder().build();
MyRoutingDataSource ds = new MyRoutingDataSource();
ds.setCurrentDS(firstDS);
return ds;
}
#Bean("firstDSproperties")
#ConfigurationProperties("datasource.first")
public DataSourceProperties firstDataSourceProperties() {
return new DataSourceProperties();
}
#Bean("secondDSproperties")
#ConfigurationProperties("datasource.second")
public DataSourceProperties secondDataSourceProperties() {
return new DataSourceProperties();
}
What this code does is to make two beans of type DataSourceProperties rather than type DataSource. With DataSourceProperties beans you can still let Spring autowire your config without (hopefully) having the cyclical dependency problem caused by having multiple beans of type DataSource depending on each other.
I haven't tested doing this with DataSourceProperties since I am not using DataSourceAutoConfiguration in my code. But based on your code I think it might work.
There is slight a mistake here. Let me explain you with foo and bar DB example along with git repo reference.
Here is how your application.properties look like
# Oracle DB - "foo"
spring.datasource.url=jdbc:oracle:thin:#//db-server-foo:1521/FOO
spring.datasource.username=fooadmin
spring.datasource.password=foo123
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
# PostgreSQL DB - "bar"
bar.datasource.url=jdbc:postgresql://db-server-bar:5432/bar
bar.datasource.username=baradmin
bar.datasource.password=bar123
bar.datasource.driver-class-name=org.postgresql.Driver
Set the SQL Dialect to “default” in your application.properties to let Spring autodetect the different SQL Dialects of each datasource
spring.jpa.database=default
Package should look something like
src/main/java
- com.foobar
- foo
- domain
- repo
- bar
- domain
- repo
Here is the main part. Configuration classes
Foo Configuration class (Oracle)
package com.foobar;
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactory",
basePackages = { "com.foobar.foo.repo" }
)
public class FooDbConfig {
#Primary
#Bean(name = "dataSource")
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Primary
#Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean
entityManagerFactory(
EntityManagerFactoryBuilder builder,
#Qualifier("dataSource") DataSource dataSource
) {
return builder
.dataSource(dataSource)
.packages("com.foobar.foo.domain")
.persistenceUnit("foo")
.build();
}
#Primary
#Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager(
#Qualifier("entityManagerFactory") EntityManagerFactory
entityManagerFactory
) {
return new JpaTransactionManager(entityManagerFactory);
}
}
Bar Configuration class (postgres)
package com.foobar;
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "barEntityManagerFactory",
transactionManagerRef = "barTransactionManager",
basePackages = { "com.foobar.bar.repo" }
)
public class BarDbConfig {
#Bean(name = "barDataSource")
#ConfigurationProperties(prefix = "bar.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "barEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean
barEntityManagerFactory(
EntityManagerFactoryBuilder builder,
#Qualifier("barDataSource") DataSource dataSource
) {
return
builder
.dataSource(dataSource)
.packages("com.foobar.bar.domain")
.persistenceUnit("bar")
.build();
}
#Bean(name = "barTransactionManager")
public PlatformTransactionManager barTransactionManager(
#Qualifier("barEntityManagerFactory") EntityManagerFactory
barEntityManagerFactory
) {
return new JpaTransactionManager(barEntityManagerFactory);
}
}
Your repositories would look something like
package com.foobar.bar.repo;
#Repository
public interface BarRepository extends JpaRepository<Bar, Long> {
Bar findById(Long id);
}
package com.foobar.foo.repo;
#Repository
public interface FooRepository extends JpaRepository<Foo, Long> {
Foo findById(Long id);
}
And you are done here.
You can refer code on github here
I am working on an application that uses Spring Session JDBC. I also am using Spring JPA for other entities. My question is, how does one configure a Spring Boot application to allow for a separate database to be used for Session storage?
I have referenced this question, but it appears the JdbcHttpSessionConfiguration constructor noted in the answer is no longer valid (I am using Spring Boot 2.1.1). Other than that, I was unable to find any documentation on the subject. I found information on how to configure Spring Session with a JDBC backing, and how to use multiple data sources in Spring, but not how to combine the two. I reckon it might involves extending JdbcHttpSessionConfiguration, but unfortunately, I am not able to figure out how to properly do so.
This is all I have thus far:
#Configuration
class SessionConfig extends JdbcHttpSessionConfiguration {
#Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();
}
}
However, the above attempts to create all my entity tables in the H2 store as well.
My primary datasource (PostgreSQL) is specified in my application.properties.
spring.session.store-type=jdbc
spring.datasource.url=jdbc:postgresql://localhost/auth
spring.datasource.username=xxx
spring.datasource.password=xxx
spring.datasource.driverClassName=org.postgresql.Driver
spring.jpa.show-sql=true
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
Thanks for any guidance.
Since Spring Boot 2.0.0 you can specify the DataSource that Spring Session should use by using annotation #SpringSessionDataSource.
Qualifier annotation for a DataSource to be injected in
JdbcOperationsSessionRepository.
The method inside the Spring JdbcHttpSessionConfiguration class that sets the desired datasource.
#Autowired
public void setDataSource(#SpringSessionDataSource ObjectProvider<DataSource> springSessionDataSource, ObjectProvider<DataSource> dataSource)
To achieve the desired result one has to configure a secondary datasource for use in Spring Session and annotate the bean with #SpringSessionDataSource. Below is the configuration that worked for me.
application.properties
session.datasource.url=jdbc:postgresql://localhost:5432/session
session.datasource.driverClassName=org.postgresql.Driver
session.datasource.username=postgres
session.datasource.password=thepassword
primary.datasource.url=jdbc:postgresql://localhost:5432/postgres
primary.datasource.driverClassName=org.postgresql.Driver
primary.datasource.username=postgres
primary.datasource.password=thepassword
The database config
#Configuration
#EnableTransactionManagement
public class DatabaseConfig {
#Bean
#Primary
#ConfigurationProperties("primary.datasource")
public DataSourceProperties primaryDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#Primary
public DataSource primaryDataSource() {
return primaryDataSourceProperties().initializeDataSourceBuilder()
.type(HikariDataSource.class).build();
}
#Bean
#ConfigurationProperties("session.datasource")
public DataSourceProperties sessionDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#SpringSessionDataSource
public DataSource springSessionDataSource() {
return sessionDataSourceProperties().initializeDataSourceBuilder()
.type(HikariDataSource.class).build();
}
}
Remember to run the org/springframework/session/jdbc/schema-thedbplatform.sql schema file on your db if you're not using a embedded database. In my case I ran org/springframework/session/jdbc/schema-postgresql.sql.
If you want to use a H2 database for you session management you can remove the session.datasource... from your application.properties and configure your datasources as follows.
#Configuration
#EnableTransactionManagement
public class DatabaseConfig {
#Bean
#Primary
#ConfigurationProperties("primary.datasource")
public DataSourceProperties primaryDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#Primary
public DataSource primaryDataSource() {
return primaryDataSourceProperties().initializeDataSourceBuilder()
.type(HikariDataSource.class).build();
}
#Bean
#SpringSessionDataSource
public EmbeddedDatabase springSessionDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("org/springframework/session/jdbc/schema-h2.sql").build();
}
}
I'm using Spring Boot autoconfigured Spring Batch setup with #EnableBatchProcessing. The problem is that it creates metadata tables in the main database and I don't want this behavior. I would like to save all the Spring Batch information to an embedded database.
I've tried using the spring.batch.initialize-schema=embedded property and adding H2 to the classpath, overriding DefaultBatchConfigurer bean with the H2 data source, replacing JobRepository and JobLauncher beans but it constantly creates metadata tables in the main Oracle database. I'm using Spring Batch 3.0.8 and Spring Boot 1.5.9.
Any help is appreciated, thank you!
UPDATE: Adding come configuration:
H2 config:
#Bean
public DataSource springBatchDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:mem:db;DB_CLOSE_DELAY=-1");
dataSource.setUsername("sa");
dataSource.setPassword("sa");
return dataSource;
}
Oracle:
#Bean
#Primary
public DataSource dataSource() throws SQLException {
PoolDataSourceImpl dataSource = new PoolDataSourceImpl();
dataSource.setConnectionFactoryClassName(environment.getRequiredProperty("db.driverClassName"));
dataSource.setURL(environment.getRequiredProperty("db.url"));
dataSource.setUser(environment.getRequiredProperty("db.username"));
dataSource.setPassword(environment.getRequiredProperty("db.password"));
dataSource.setFastConnectionFailoverEnabled(Boolean.valueOf(environment
.getRequiredProperty("db.fast.connect.failover.enabled")));
dataSource.setValidateConnectionOnBorrow(true);
dataSource.setSQLForValidateConnection("SELECT SYSDATE FROM DUAL");
dataSource.setONSConfiguration(environment.getRequiredProperty("db.ons.config"));
dataSource.setInitialPoolSize(Integer.valueOf(environment.getRequiredProperty("db.initial.pool.size")));
dataSource.setMinPoolSize(Integer.valueOf(environment.getRequiredProperty("db.min.pool.size")));
dataSource.setMaxPoolSize(Integer.valueOf(environment.getRequiredProperty("db.max.pool.size")));
dataSource.setAbandonedConnectionTimeout(120);
dataSource.setInactiveConnectionTimeout(360);
dataSource.setTimeToLiveConnectionTimeout(0);
return dataSource;
}
Batch configuration:
#Configuration
#EnableBatchProcessing
public class BatchConfigurer extends DefaultBatchConfigurer {
#Override
#Autowired
public void setDataSource(#Qualifier("springBatchDataSource") DataSource dataSource) {
super.setDataSource(dataSource);
}
}
and some properties related..
spring:
batch:
job.enabled: false
1.redefine the BasicBatchConfigurer
2.in spring-boot-batch-starter, you must create your own BatchDataSourceInitializer, so it will execute the init sql scripts
#Configuration
public class MyBatchConfigurer {
#Bean
public BasicBatchConfigurer batchConfigurer(BatchProperties properties,
#Qualifier("springBatchDataSource") DataSource dataSource,
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
return new BasicBatchConfigurer(properties, dataSource,
transactionManagerCustomizers.getIfAvailable());
}
#Bean
public BatchDataSourceInitializer batchDataSourceInitializer(#Qualifier("springBatchDataSource") DataSource dataSource,
ResourceLoader resourceLoader, BatchProperties properties) {
return new BatchDataSourceInitializer(dataSource, resourceLoader,
properties);
}
}
You need to qualify your H2 datasource bean
#Bean(name = "springBatchDataSource")
public DataSource springBatchDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.h2.Driver");
dataSource.setUrl("jdbc:h2:mem:db;DB_CLOSE_DELAY=-1");
dataSource.setUsername("sa");
dataSource.setPassword("sa");
return dataSource;
}
I hope this help.