Browse Source

Documentation for common JdbcClient query/update usage

See gh-30931
pull/30957/head
Juergen Hoeller 3 years ago
parent
commit
49c4b205e4
  1. 110
      framework-docs/modules/ROOT/pages/data-access/jdbc/core.adoc

110
framework-docs/modules/ROOT/pages/data-access/jdbc/core.adoc

@ -6,6 +6,7 @@ including error handling. It includes the following topics:
* xref:data-access/jdbc/core.adoc#jdbc-JdbcTemplate[Using `JdbcTemplate`] * xref:data-access/jdbc/core.adoc#jdbc-JdbcTemplate[Using `JdbcTemplate`]
* xref:data-access/jdbc/core.adoc#jdbc-NamedParameterJdbcTemplate[Using `NamedParameterJdbcTemplate`] * xref:data-access/jdbc/core.adoc#jdbc-NamedParameterJdbcTemplate[Using `NamedParameterJdbcTemplate`]
* xref:data-access/jdbc/core.adoc#jdbc-JdbcClient[Unified JDBC Query/Update Operations: `JdbcClient`]
* xref:data-access/jdbc/core.adoc#jdbc-SQLExceptionTranslator[Using `SQLExceptionTranslator`] * xref:data-access/jdbc/core.adoc#jdbc-SQLExceptionTranslator[Using `SQLExceptionTranslator`]
* xref:data-access/jdbc/core.adoc#jdbc-statements-executing[Running Statements] * xref:data-access/jdbc/core.adoc#jdbc-statements-executing[Running Statements]
* xref:data-access/jdbc/core.adoc#jdbc-statements-querying[Running Queries] * xref:data-access/jdbc/core.adoc#jdbc-statements-querying[Running Queries]
@ -501,8 +502,8 @@ extend from it, your sub-class inherits a `setDataSource(..)` method from the
Regardless of which of the above template initialization styles you choose to use (or Regardless of which of the above template initialization styles you choose to use (or
not), it is seldom necessary to create a new instance of a `JdbcTemplate` class each not), it is seldom necessary to create a new instance of a `JdbcTemplate` class each
time you want to run SQL. Once configured, a `JdbcTemplate` instance is thread-safe. time you want to run SQL. Once configured, a `JdbcTemplate` instance is thread-safe.
If your application accesses multiple If your application accesses multiple databases, you may want multiple `JdbcTemplate`
databases, you may want multiple `JdbcTemplate` instances, which requires multiple `DataSources` and, subsequently, multiple differently instances, which requires multiple `DataSources` and, subsequently, multiple differently
configured `JdbcTemplate` instances. configured `JdbcTemplate` instances.
@ -531,11 +532,8 @@ Java::
} }
public int countOfActorsByFirstName(String firstName) { public int countOfActorsByFirstName(String firstName) {
String sql = "select count(*) from t_actor where first_name = :first_name";
String sql = "select count(*) from T_ACTOR where first_name = :first_name";
SqlParameterSource namedParameters = new MapSqlParameterSource("first_name", firstName); SqlParameterSource namedParameters = new MapSqlParameterSource("first_name", firstName);
return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class); return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class);
} }
---- ----
@ -547,7 +545,7 @@ Kotlin::
private val namedParameterJdbcTemplate = NamedParameterJdbcTemplate(dataSource) private val namedParameterJdbcTemplate = NamedParameterJdbcTemplate(dataSource)
fun countOfActorsByFirstName(firstName: String): Int { fun countOfActorsByFirstName(firstName: String): Int {
val sql = "select count(*) from T_ACTOR where first_name = :first_name" val sql = "select count(*) from t_actor where first_name = :first_name"
val namedParameters = MapSqlParameterSource("first_name", firstName) val namedParameters = MapSqlParameterSource("first_name", firstName)
return namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Int::class.java)!! return namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Int::class.java)!!
} }
@ -579,12 +577,9 @@ Java::
} }
public int countOfActorsByFirstName(String firstName) { public int countOfActorsByFirstName(String firstName) {
String sql = "select count(*) from t_actor where first_name = :first_name";
String sql = "select count(*) from T_ACTOR where first_name = :first_name";
Map<String, String> namedParameters = Collections.singletonMap("first_name", firstName); Map<String, String> namedParameters = Collections.singletonMap("first_name", firstName);
return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class);
return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class);
} }
---- ----
@ -596,7 +591,7 @@ Kotlin::
private val namedParameterJdbcTemplate = NamedParameterJdbcTemplate(dataSource) private val namedParameterJdbcTemplate = NamedParameterJdbcTemplate(dataSource)
fun countOfActorsByFirstName(firstName: String): Int { fun countOfActorsByFirstName(firstName: String): Int {
val sql = "select count(*) from T_ACTOR where first_name = :first_name" val sql = "select count(*) from t_actor where first_name = :first_name"
val namedParameters = mapOf("first_name" to firstName) val namedParameters = mapOf("first_name" to firstName)
return namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Int::class.java)!! return namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Int::class.java)!!
} }
@ -644,7 +639,6 @@ Java::
} }
// setters omitted... // setters omitted...
} }
---- ----
@ -673,12 +667,9 @@ Java::
} }
public int countOfActors(Actor exampleActor) { public int countOfActors(Actor exampleActor) {
// notice how the named parameters match the properties of the above 'Actor' class // notice how the named parameters match the properties of the above 'Actor' class
String sql = "select count(*) from T_ACTOR where first_name = :firstName and last_name = :lastName"; String sql = "select count(*) from t_actor where first_name = :firstName and last_name = :lastName";
SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(exampleActor); SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(exampleActor);
return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class); return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class);
} }
---- ----
@ -694,7 +685,7 @@ Kotlin::
fun countOfActors(exampleActor: Actor): Int { fun countOfActors(exampleActor: Actor): Int {
// notice how the named parameters match the properties of the above 'Actor' class // notice how the named parameters match the properties of the above 'Actor' class
val sql = "select count(*) from T_ACTOR where first_name = :firstName and last_name = :lastName" val sql = "select count(*) from t_actor where first_name = :firstName and last_name = :lastName"
val namedParameters = BeanPropertySqlParameterSource(exampleActor) val namedParameters = BeanPropertySqlParameterSource(exampleActor)
return namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Int::class.java)!! return namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Int::class.java)!!
} }
@ -707,8 +698,85 @@ functionality that is present only in the `JdbcTemplate` class, you can use the
`getJdbcOperations()` method to access the wrapped `JdbcTemplate` through the `getJdbcOperations()` method to access the wrapped `JdbcTemplate` through the
`JdbcOperations` interface. `JdbcOperations` interface.
See also xref:data-access/jdbc/core.adoc#jdbc-JdbcTemplate-idioms[`JdbcTemplate` Best Practices] for guidelines on using the See also xref:data-access/jdbc/core.adoc#jdbc-JdbcTemplate-idioms[`JdbcTemplate` Best Practices]
`NamedParameterJdbcTemplate` class in the context of an application. for guidelines on using the `NamedParameterJdbcTemplate` class in the context of an application.
[[jdbc-JdbcClient]]
== Unified JDBC Query/Update Operations: `JdbcClient`
As of 6.1, the named parameter statements of `NamedParameterJdbcTemplate` and the positional
parameter statements of a regular `JdbcTemplate` are available through a unified client API
with a fluent interaction model.
E.g. with named parameters:
[source,java,indent=0,subs="verbatim,quotes"]
----
private JdbcClient jdbcClient = JdbcClient.create(dataSource);
public int countOfActorsByFirstName(String firstName) {
return this.jdbcClient.sql("select count(*) from t_actor where first_name = :first_name")
.param("first_name", firstName);
.query().singleValue(Integer.class);
}
----
E.g. with positional parameters:
[source,java,indent=0,subs="verbatim,quotes"]
----
private JdbcClient jdbcClient = JdbcClient.create(dataSource);
public int countOfActorsByFirstName(String firstName) {
return this.jdbcClient.sql("select count(*) from t_actor where first_name = ?")
.param(firstName);
.query().singleValue(Integer.class);
}
----
`RowMapper` capabilities are available as well, with flexible result resolution:
[source,java,indent=0,subs="verbatim,quotes"]
----
List<Actor> actors = this.jdbcClient.sql("select first_name, last_name from t_actor")
.query((rs, rowNum) -> new Actor(rs.getString("first_name"), rs.getString("last_name")))
.list();
----
With a required single object result:
[source,java,indent=0,subs="verbatim,quotes"]
----
Actor actor = this.jdbcClient.sql("select first_name, last_name from t_actor where id = ?",
.param(1212L);
.query((rs, rowNum) -> new Actor(rs.getString("first_name"), rs.getString("last_name")))
.single();
----
With a `java.util.Optional` result:
[source,java,indent=0,subs="verbatim,quotes"]
----
Optional<Actor> actor = this.jdbcClient.sql("select first_name, last_name from t_actor where id = ?",
.param(1212L);
.query((rs, rowNum) -> new Actor(rs.getString("first_name"), rs.getString("last_name")))
.optional();
----
And for an update statement:
[source,java,indent=0,subs="verbatim,quotes"]
----
this.jdbcClient.sql("insert into t_actor (first_name, last_name) values (?, ?)")
.param("Leonor").param("Watling");
.update();
----
NOTE: `JdbcClient` is a flexible but simplified facade for JDBC query/update statements.
Advanced capabilities such as batch inserts and stored procedure calls typically require
extra customization: consider Spring's `SimpleJdbcInsert` and `SimpleJdbcCall` classes or
plain direct `JdbcTemplate` usage for any such capabilities not available on `JdbcClient`.
[[jdbc-SQLExceptionTranslator]] [[jdbc-SQLExceptionTranslator]]

Loading…
Cancel
Save