About FluentJdbc
FluentJdbc is a java library for operating with SQL queries conveniently. Every SQL operation is a single, readable api call without any of the JDBC clutter. It supports functionality that most similar jdbc wrappers prevent or abstract away, more details below.
FluentJdbc's key features:
- functional, fluent API
- execution of select/insert/update/delete/alter/... statements as one-liners
- parameter mapping (named, positional, supports java.time, Collection parameters, plugins for custom types)
- accessing generated keys of insert/update queries
- transaction handling
- big data (scalable, streaming style of batch and select)
- automatic result to pojo mapping
- database inspection
<dependency>
<groupId>org.codejargon</groupId>
<artifactId>fluentjdbc</artifactId>
<version>1.3.4</version>
</dependency>
Note: requires java 8
Full documentation on wiki
Latest javadoc
News
Code examples of common use cases
Setting up FluentJdbc
DataSource dataSource = ...
Fluent Jdbc fluentJdbc = new FluentJdbcBuilder()
.connectionProvider(dataSource)
.build();
Query query = fluentJdbc.query();
// ... use the Query interface for queries (thread-safe, reentrant)
DataSource dataSource = ...
Fluent Jdbc fluentJdbc = new FluentJdbcBuilder()
.connectionProvider(dataSource)
.build();
Query query = fluentJdbc.query();
// ... use the Query interface for queries (thread-safe, reentrant)
Note: using a DataSource is the most common, there are other alternatives documented on the wiki
Update or insert queries
query
.update("UPDATE CUSTOMER SET NAME = ?, ADDRESS = ?")
.params("John Doe", "Dallas")
.run();
Query for a list of results
List<Customer> customers = query
.select("SELECT * FROM CUSTOMER WHERE NAME = ?")
.params("John Doe")
.listResult(customerMapper);
Mapping of results
Mapper can be implemented manually
resultSet -> new Customer(resultSet.getString("NAME"), resultSet.getString("ADDRESS"));
or mapping can be performed automatically to a java object
ObjectMappers objectMappers = ObjectMappers.builder().build(); //typically one instance per app
...
Mapper<Customer> customerMapper = objectMappers.forClass(Customer.class);
Query for single result
Long count = query
.select("SELECT COUNT(*) FROM CUSTOMER WHERE NAME = ?")
.params("John Doe")
.singleResult(Mappers.singleLong);
Query for first result
Optional<Customer> customer = query
.select("SELECT FROM CUSTOMER WHERE NAME = ?")
.params("John Doe")
.firstResult(customerMapper);
Batch insert or update
Iterator<List<Object>> params = ...; // or Stream/Iterable
query
.batch("INSERT INTO CUSTOMER(NAME, ADDRESS) VALUES(?, ?)")
.params(params)
.run();
Named parameters
Map<String, Object> namedParams = new HashMap<>();
namedParams.put("name", "John Doe");
namedParams.put("address", "Dallas");
query
.batch("UPDATE CUSTOMER SET NAME = :name, ADDRESS = :address")
.namedParams(namedParams)
.run();
java.time support for query parameters
query
.update("UPDATE CUSTOMER SET DEADLINE = ?, UPDATED = ?")
.params(LocalDate.of(2015, Month.MARCH, 5), Instant.now())
.run();
Iterating a large resultset
query
.select("SELECT * FROM CUSTOMER")
.iterateResult(customerMapper, (customer) -> {
if(customer.isExpired()) {
...
}
});
Query for a list of limited results
List<Customer> customers = query
.select("SELECT * FROM CUSTOMER WHERE NAME = ?")
.params("John Doe")
.maxRows(345L)
.listResult(customerMapper);
Fetching generated key of an insert or updates
UpdateResultGenKeys<Long> result = query
.update("INSERT INTO CUSTOMER(NAME) VALUES(:name)")
.namedParams(namedParams)
.runFetchGenKeys(Mappers.singleLong());
Long id = result.generatedKeys().get(0);
Querying using a specific connection object
Connection connection = ...
Query query = fluentJdbc.queryOn(connection);
// do some querying...
Transactions
query.transaction().in(
() -> {
query
.update("UPDATE CUSTOMER SET NAME = ?, ADDRESS = ?")
.params("John Doe", "Dallas")
.run();
someOtherBusinessOperationAlsoNeedingTransactions();
}
)
All queries executed in the block will be part of the transaction - in the same thread, based on the same FluentJdbc/ConnectionProvider. Exceptions cause rollback. It is possible to use multiple transactions/datasources simultaneously.
Refer to the full documentation for more details and code examples.