Skip to content

Instantly share code, notes, and snippets.

@trasa
Created January 31, 2019 22:03
Show Gist options
  • Save trasa/1fbc60dc130231898273013492904e64 to your computer and use it in GitHub Desktop.
Save trasa/1fbc60dc130231898273013492904e64 to your computer and use it in GitHub Desktop.
JDBI 3 SpringBoot 4 Example
@Slf4j
@EnableSwagger2
@SpringBootApplication
@EnableScheduling
@SuppressWarnings("unused")
public class Application extends SpringBootServletInitializer {
/**
* Create our JDBI singleton. Configure plugins. Set options, pooling, etc.
*
* @return Jdbi instance
*/
@Bean
public Jdbi db() {
// connect to in memory db
// DB_CLOSE_DELAY=-1 says to keep the db around as long as
// the JVM is live (otherwise its gone as soon as there's no
// connections...leading to errors about insert failing because
// the table doesn't exist.
Jdbi jdbi = Jdbi.create("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1");
jdbi.installPlugin(new SqlObjectPlugin());
// just for testing, create an in-memory table:
jdbi.useHandle(h -> h.execute("create table example (id integer primary key, name varchar)"));
jdbi.useHandle(h -> h.execute("insert into example (id, name) values (1, 'foo')"));
return jdbi;
}
/**
* Wire up our ExampleDao to spring.
*
* While I generally like the explicit approach, there are
* ways to have the wiring of @Repository beans happen
* automatically.
*
* @param jdbi
* @return
*/
@Bean
public ExampleDao exampleDao(Jdbi jdbi) {
return jdbi.onDemand(ExampleDao.class);
}
}
/**
* It's an Example DTO. So exciting.
*/
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class Example {
int id;
String name;
}
/**
* A very simple, boring Repository for our Example Beans.
*
* See http://jdbi.org/#_introduction_to_jdbi
*
*
* There's a lot of cool stuff that we can do using JDBI and the various
* mappers. Not showing that stuff here.
*
* Note that there are a few different ways to tie Spring and JDBI
* together, depending on how much spring-data and transaction management
* you want (i.e. how much like Hibernate/JPA do you want to be)... I
* prefer to keep things simple and avoid spring-data, JPA, and so on
* unless there's a really good cause for otherwise.
*/
@Repository
@RegisterBeanMapper(Example.class)
public interface ExampleDao {
@SqlUpdate("insert into example (id, name) values (:id, :name)")
void add(@BindBean Example ex);
@SqlQuery("select * from example")
List<Example> getAll();
}
<project>
<properties>
<lib.jdbi.version>3.6.0</lib.jdbi.version>
...
</properties>
<plugin>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
<!-- JDBI 3 has a whole bunch of different modules.
http://jdbi.org/#_modules
I'm just doing the basics, particularly not getting
too far into things like jdbi3-spring4 integration.
-->
<dependency>
<groupId>org.jdbi</groupId>
<artifactId>jdbi3-core</artifactId>
<version>${lib.jdbi.version}</version>
</dependency>
<dependency>
<groupId>org.jdbi</groupId>
<artifactId>jdbi3-sqlobject</artifactId>
<version>${lib.jdbi.version}</version>
</dependency>
<!-- test db: in memory database -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.197</version>
</dependency>
...
</project>
@Machine-Maker
Copy link

I've been looking around for a while trying to figure out how to have spring automatically use jdbi's on-demand for @ Repository-annotated interfaces but I cant seem to find anything. You mention there are ways, can you point me towards one?

@trasa
Copy link
Author

trasa commented Jun 9, 2021

It has been a long while since I've looked at this code, and I don't spend much time in Spring anymore. But, from what I recall, there were a couple of options - using the @ComponentScan annotation to tell spring where to find your @Repositorys, and then having them take a Jdbi in their ctor. Then you're not using the interface and onDemand creation, which I don't think is a good tradeoff.

Or, better - use a package like Reflections and filters to find all classes annotated with Repository, and then for each, call jdbi.onDemand(class) - this is what I've used to autowire message handlers when there's an arbitrary number of them and I definitely don't want to load them one at a time.

Sometimes I get pushback on using Reflections on startup like this as being "too magical", but hey, I like magic, that's why we were using Spring...

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