Jdbi: Docs / Example: Provide example (repo) to show how to integrate jdbi3 in spring-boot

Created on 20 Feb 2018  ·  10Comments  ·  Source: jdbi/jdbi

I'd like to integrate jdbi3 into spring-boot. But it's hard to find all required pieces in the internet to get the full picture.
Is there any chance to provide an jdbi-examples-repository on github, that just showcases how to setup a spring-boot application with jdbi3?

I'd appreciate that very much. Thanks a lot.
/Seb

doc help wanted improvement

Most helpful comment

I've been using the following method with jdbi2.x without any problems. Have been testing it out with jdbi3.x and haven't seen any issues. This looks like a simpler way to get spring to manage transactions while using jdbi.

Basically you wrap the proxy with a TransactionAwareDataSourceProxy and use that to create the Jdbi instance. (I have c/p'd from @arteam 's answer so that the examples are consistent)

    @Bean
    public DataSource dataSource() {
        // From Spring Boot's connection pool configuration;
    }

    @Bean
    public TransactionAwareDataSourceProxy txDataSource(DataSource dataSource) {
        return new TransactionAwareDataSourceProxy(dataSource);
    }

    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        //not sure if this is needed
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean
    public Jdbi createJdbi(TransactionAwareDataSourceProxy dataSource) {
        //note that parameter is TransactionAwareDataSourceProxy instead of plain DataSource
        return Jdbi.create(dataSource);
    }

    @Bean
    public UserDao userDao(Jdbi jdbi) {
        return jdbi.onDemand(UserDao.class);
    }

All 10 comments

In a simple case, if you don't need an integration with the Spring's transaction facilities, you can just just initialize Jdbi and your DAOs in a Spring configuration:

    @Bean
    public DataSource dataSource() {
        // From Spring Boot's connection pool configuration;
    }

    @Bean
    public Jdbi createJdbi(DataSource dataSource) {
        return Jdbi.create(dataSource);
    }

    @Bean
    public UserDao userDao(Jdbi jdbi) {
        return jdbi.onDemand(UserDao.class);
    }

hi @bastman , @alwins0n is contributing better Spring support in #989 - would you like to review his work so far and comment on whether it makes your Spring integration clearer, or if you are asking for something slightly different?

Integrating jdbi to spring boot is trivial, you just need set up a @Bean annotated method in your @Configuration class to return a Jdbi instance - as shown by @arteam

The harder thing, as done in my spring PR, is integrating jdbi into the spring transaction management. You should definitly check it out, if it is what you are looking for.

Furthermore, if this gets approved I am considering to create an autoconfiguration/spring-boot-starter for spring boot (2). if that is what you are looking for. (it actually is a good excersize if you want to try yourself: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-auto-configuration.html )

I've been using the following method with jdbi2.x without any problems. Have been testing it out with jdbi3.x and haven't seen any issues. This looks like a simpler way to get spring to manage transactions while using jdbi.

Basically you wrap the proxy with a TransactionAwareDataSourceProxy and use that to create the Jdbi instance. (I have c/p'd from @arteam 's answer so that the examples are consistent)

    @Bean
    public DataSource dataSource() {
        // From Spring Boot's connection pool configuration;
    }

    @Bean
    public TransactionAwareDataSourceProxy txDataSource(DataSource dataSource) {
        return new TransactionAwareDataSourceProxy(dataSource);
    }

    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        //not sure if this is needed
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean
    public Jdbi createJdbi(TransactionAwareDataSourceProxy dataSource) {
        //note that parameter is TransactionAwareDataSourceProxy instead of plain DataSource
        return Jdbi.create(dataSource);
    }

    @Bean
    public UserDao userDao(Jdbi jdbi) {
        return jdbi.onDemand(UserDao.class);
    }

looks good, I did not know that this class existed.

could you have a look in the PR mentioned earlier? there has been already a suggestion been made regaring a "transaction aware" connection factory underlying to jdbi.

iirc the problem remains that connection and handle is not in-sync state wise. so this ds returns a connection (which is bound to the transaction) which is closed on transaction end. whereas the used handle is not closed and throws exceptions on attempt to (re-) use it.

but maybe this is not so big of a deal and rather corner case-y and your solution fits for 99% of use cases.

in short: with your approach the transaction managed resource is the connection. in my PR the managed resourced is the handle.

There is problems related to using jdbi3 with stringtemplate4 and group imports. See my issue https://github.com/jdbi/jdbi/issues/1052
This issue also includes a link to a fully working repo skeleton for using jdbi3 in spring boot 2.0.0

When i implement @kaandok 's solution with Spring's @Transactional annotation, i get following exception due to closing handles when there exists open transactions. Is there any recommended/applicable solution for that?

"Improper transaction handling detected: A Handle with an open transaction was closed. Transactions must be explicitly committed or rolled back before closing the Handle. Jdbi has rolled back this transaction automatically. "

@cengha can you provide some code demonstrating your issue please?

Below is config class:

@Bean
public HikariDataSource hikariDataSource() {
    HikariConfig dataSourceConfig = new HikariConfig();
    dataSourceConfig.setDriverClassName(driverClassName);
    dataSourceConfig.setJdbcUrl(jdbcUrl);
    dataSourceConfig.setUsername(username);
    dataSourceConfig.setPassword(password);
    dataSourceConfig.setAutoCommit(true);
    return new HikariDataSource(dataSourceConfig);
}

@Bean
public TransactionAwareDataSourceProxy transactionAwareDataSourceProxy(HikariDataSource dataSource) {
    return new TransactionAwareDataSourceProxy(dataSource);
}

@Bean
public PlatformTransactionManager platformTransactionManager(HikariDataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
}

@Bean
public Jdbi jdbi(TransactionAwareDataSourceProxy transactionAwareDataSourceProxy) {
    Jdbi jdbi = Jdbi.create(transactionAwareDataSourceProxy);
    jdbi.installPlugin(new SqlObjectPlugin());
    return jdbi;
}

Here is service layer

    @Override
    @Transactional
    public Long createX(X x) {
        Long aLong = XDao.insertX(x);
        if(true) throw new RuntimeException();
        return aLong;
    }

When auto-commit is set to false i got mentioned transaction error but if it set to true there is not any transaction error but this time rollback does not work (after runtime exception) and so X object is being persisted to database. I use spring 2.0.3, JDBI 3.0.0-beta2 .

Problem solved. I was using older version of JDBI, after noticing this thread updated the library and everything resolved.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

qualidafial picture qualidafial  ·  3Comments

rherrmann picture rherrmann  ·  4Comments

Shujito picture Shujito  ·  5Comments

stevenschlansker picture stevenschlansker  ·  4Comments

bakstad picture bakstad  ·  5Comments