Skip to content

Instantly share code, notes, and snippets.

@dakoctba
Last active August 15, 2024 07:34
Show Gist options
  • Select an option

  • Save dakoctba/1047ca084118ff46a1a917726f99a2b2 to your computer and use it in GitHub Desktop.

Select an option

Save dakoctba/1047ca084118ff46a1a917726f99a2b2 to your computer and use it in GitHub Desktop.
Spring Boot + JDBI + Multiple Databases
import java.util.List;
import javax.sql.DataSource;
import org.jdbi.v3.core.Jdbi;
import org.jdbi.v3.core.mapper.RowMapper;
import org.jdbi.v3.core.spi.JdbiPlugin;
import org.jdbi.v3.sqlobject.SqlObjectPlugin;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
import br.com.company.produto.dao.dominio.CityDAO;
import br.com.company.produto.dao.dw.ProfessionDAO;
@Configuration
public class AppConfig {
@Bean("jdbi-1")
public Jdbi jdbi(@Qualifier("datasource1") DataSource ds, List<JdbiPlugin> plugins, List<RowMapper<?>> mappers) {
TransactionAwareDataSourceProxy proxy = new TransactionAwareDataSourceProxy(ds);
Jdbi jdbi = Jdbi.create(proxy);
plugins.forEach(plugin -> jdbi.installPlugin(plugin));
mappers.forEach(mapper -> jdbi.registerRowMapper(mapper));
return jdbi;
}
@Bean("jdbi-2")
public Jdbi secondaryJdbi(@Qualifier("datasource2") DataSource ds, List<JdbiPlugin> plugins, List<RowMapper<?>> mappers) {
TransactionAwareDataSourceProxy proxy = new TransactionAwareDataSourceProxy(ds);
Jdbi jdbi = Jdbi.create(proxy);
plugins.forEach(plugin -> jdbi.installPlugin(plugin));
mappers.forEach(mapper -> jdbi.registerRowMapper(mapper));
return jdbi;
}
@Bean
public JdbiPlugin sqlObjectPlugin() {
return new SqlObjectPlugin();
}
@Bean
public CityDAO cityDao(@Qualifier("jdbi-1") Jdbi jdbi) {
return jdbi.onDemand(CityDAO.class);
}
@Bean
public ProfessionDAO professionDao(@Qualifier("jdbi-2") Jdbi jdbi) {
return jdbi.onDemand(ProfessionDAO.class);
}
}
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults=false
spring.jpa.database=default
#
# Primary database
#
spring.datasource.db1.jdbcUrl=jdbc:postgresql://localhost:5432/<database>
spring.datasource.db1.driver-class-name=org.postgresql.Driver
spring.datasource.db1.username=postgres
spring.datasource.db1.password=postgres
#
# Secondary database
#
spring.datasource.db2.jdbcUrl=jdbc:postgresql://localhost:5432/<database>
spring.datasource.db2.driver-class-name=org.postgresql.Driver
spring.datasource.db2.username=postgres
spring.datasource.db2.password=postgres
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
@Configuration
public class DataSourceConfig {
@Bean(name = "datasource1")
@ConfigurationProperties("spring.datasource.db1")
@Primary
public DataSource db1Datasource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "datasource2")
@ConfigurationProperties("spring.datasource.db2")
public DataSource db2Datasource() {
return DataSourceBuilder.create().build();
}
@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;
}
}
@thiagomuller

Copy link
Copy Markdown

Nice!!

@d2k2-git

d2k2-git commented Jan 14, 2024

Copy link
Copy Markdown

can you explain for what the DataSourceTransactionManager Bean is required for?
From my experience it's enough to use TransactionAwareDataSourceProxy to make springs @Transactional annotation working with jdbi.

Also according to the jdbi documention you should use Spring SpringConnectionFactory instead TransactionAwareDataSourceProxy to create a JDBI bean instance.

see: https://jdbi.org/#_annotation_based_configuration

@Configuration
public class JdbiConfiguration {
    @Bean
    public Jdbi jdbi(DataSource ds) {
        ConnectionFactory cf = new SpringConnectionFactory(dataSource); 
        final Jdbi jdbi = Jdbi.create(cf);
        /* additional configuration goes here */
        return jdbi;
    }
}

@ValeryVasilyev

Copy link
Copy Markdown

This code doesn't run for me cuz of exception
No qualifying bean of type 'org.jdbi.v3.core.Jdbi' available: expected single matching bean but found 2: jdbi-1,jdbi-2
But it fixes by annotating with @primary for some of jdbi Bean, e.g.:
@Bean(value = "jdbi-1")
@Primary
public Jdbi jdbi()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment