@@ -6,6 +6,7 @@ including error handling. It includes the following topics:
6
6
7
7
* xref:data-access/jdbc/core.adoc#jdbc-JdbcTemplate[Using `JdbcTemplate`]
8
8
* xref:data-access/jdbc/core.adoc#jdbc-NamedParameterJdbcTemplate[Using `NamedParameterJdbcTemplate`]
9
+ * xref:data-access/jdbc/core.adoc#jdbc-JdbcClient[Unified JDBC Query/Update Operations: `JdbcClient`]
9
10
* xref:data-access/jdbc/core.adoc#jdbc-SQLExceptionTranslator[Using `SQLExceptionTranslator`]
10
11
* xref:data-access/jdbc/core.adoc#jdbc-statements-executing[Running Statements]
11
12
* 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
501
502
Regardless of which of the above template initialization styles you choose to use (or
502
503
not), it is seldom necessary to create a new instance of a `JdbcTemplate` class each
503
504
time you want to run SQL. Once configured, a `JdbcTemplate` instance is thread-safe.
504
- If your application accesses multiple
505
- databases, you may want multiple `JdbcTemplate` instances, which requires multiple `DataSources` and, subsequently, multiple differently
505
+ If your application accesses multiple databases, you may want multiple `JdbcTemplate`
506
+ instances, which requires multiple `DataSources` and, subsequently, multiple differently
506
507
configured `JdbcTemplate` instances.
507
508
508
509
@@ -531,11 +532,8 @@ Java::
531
532
}
532
533
533
534
public int countOfActorsByFirstName(String firstName) {
534
-
535
- String sql = "select count(*) from T_ACTOR where first_name = :first_name";
536
-
535
+ String sql = "select count(*) from t_actor where first_name = :first_name";
537
536
SqlParameterSource namedParameters = new MapSqlParameterSource("first_name", firstName);
538
-
539
537
return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class);
540
538
}
541
539
----
@@ -547,7 +545,7 @@ Kotlin::
547
545
private val namedParameterJdbcTemplate = NamedParameterJdbcTemplate(dataSource)
548
546
549
547
fun countOfActorsByFirstName(firstName: String): Int {
550
- val sql = "select count(*) from T_ACTOR where first_name = :first_name"
548
+ val sql = "select count(*) from t_actor where first_name = :first_name"
551
549
val namedParameters = MapSqlParameterSource("first_name", firstName)
552
550
return namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Int::class.java)!!
553
551
}
@@ -579,12 +577,9 @@ Java::
579
577
}
580
578
581
579
public int countOfActorsByFirstName(String firstName) {
582
-
583
- String sql = "select count(*) from T_ACTOR where first_name = :first_name";
584
-
580
+ String sql = "select count(*) from t_actor where first_name = :first_name";
585
581
Map<String, String> namedParameters = Collections.singletonMap("first_name", firstName);
586
-
587
- return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class);
582
+ return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class);
588
583
}
589
584
----
590
585
@@ -596,7 +591,7 @@ Kotlin::
596
591
private val namedParameterJdbcTemplate = NamedParameterJdbcTemplate(dataSource)
597
592
598
593
fun countOfActorsByFirstName(firstName: String): Int {
599
- val sql = "select count(*) from T_ACTOR where first_name = :first_name"
594
+ val sql = "select count(*) from t_actor where first_name = :first_name"
600
595
val namedParameters = mapOf("first_name" to firstName)
601
596
return namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Int::class.java)!!
602
597
}
@@ -644,7 +639,6 @@ Java::
644
639
}
645
640
646
641
// setters omitted...
647
-
648
642
}
649
643
----
650
644
@@ -673,12 +667,9 @@ Java::
673
667
}
674
668
675
669
public int countOfActors(Actor exampleActor) {
676
-
677
670
// notice how the named parameters match the properties of the above 'Actor' class
678
- String sql = "select count(*) from T_ACTOR where first_name = :firstName and last_name = :lastName";
679
-
671
+ String sql = "select count(*) from t_actor where first_name = :firstName and last_name = :lastName";
680
672
SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(exampleActor);
681
-
682
673
return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class);
683
674
}
684
675
----
@@ -694,7 +685,7 @@ Kotlin::
694
685
695
686
fun countOfActors(exampleActor: Actor): Int {
696
687
// notice how the named parameters match the properties of the above 'Actor' class
697
- val sql = "select count(*) from T_ACTOR where first_name = :firstName and last_name = :lastName"
688
+ val sql = "select count(*) from t_actor where first_name = :firstName and last_name = :lastName"
698
689
val namedParameters = BeanPropertySqlParameterSource(exampleActor)
699
690
return namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Int::class.java)!!
700
691
}
@@ -707,8 +698,85 @@ functionality that is present only in the `JdbcTemplate` class, you can use the
707
698
`getJdbcOperations()` method to access the wrapped `JdbcTemplate` through the
708
699
`JdbcOperations` interface.
709
700
710
- See also xref:data-access/jdbc/core.adoc#jdbc-JdbcTemplate-idioms[`JdbcTemplate` Best Practices] for guidelines on using the
711
- `NamedParameterJdbcTemplate` class in the context of an application.
701
+ See also xref:data-access/jdbc/core.adoc#jdbc-JdbcTemplate-idioms[`JdbcTemplate` Best Practices]
702
+ for guidelines on using the `NamedParameterJdbcTemplate` class in the context of an application.
703
+
704
+
705
+ [[jdbc-JdbcClient]]
706
+ == Unified JDBC Query/Update Operations: `JdbcClient`
707
+
708
+ As of 6.1, the named parameter statements of `NamedParameterJdbcTemplate` and the positional
709
+ parameter statements of a regular `JdbcTemplate` are available through a unified client API
710
+ with a fluent interaction model.
711
+
712
+ E.g. with named parameters:
713
+
714
+ [source,java,indent=0,subs="verbatim,quotes"]
715
+ ----
716
+ private JdbcClient jdbcClient = JdbcClient.create(dataSource);
717
+
718
+ public int countOfActorsByFirstName(String firstName) {
719
+ return this.jdbcClient.sql("select count(*) from t_actor where first_name = :first_name")
720
+ .param("first_name", firstName);
721
+ .query().singleValue(Integer.class);
722
+ }
723
+ ----
724
+
725
+ E.g. with positional parameters:
726
+
727
+ [source,java,indent=0,subs="verbatim,quotes"]
728
+ ----
729
+ private JdbcClient jdbcClient = JdbcClient.create(dataSource);
730
+
731
+ public int countOfActorsByFirstName(String firstName) {
732
+ return this.jdbcClient.sql("select count(*) from t_actor where first_name = ?")
733
+ .param(firstName);
734
+ .query().singleValue(Integer.class);
735
+ }
736
+ ----
737
+
738
+ `RowMapper` capabilities are available as well, with flexible result resolution:
739
+
740
+ [source,java,indent=0,subs="verbatim,quotes"]
741
+ ----
742
+ List<Actor> actors = this.jdbcClient.sql("select first_name, last_name from t_actor")
743
+ .query((rs, rowNum) -> new Actor(rs.getString("first_name"), rs.getString("last_name")))
744
+ .list();
745
+ ----
746
+
747
+ With a required single object result:
748
+
749
+ [source,java,indent=0,subs="verbatim,quotes"]
750
+ ----
751
+ Actor actor = this.jdbcClient.sql("select first_name, last_name from t_actor where id = ?",
752
+ .param(1212L);
753
+ .query((rs, rowNum) -> new Actor(rs.getString("first_name"), rs.getString("last_name")))
754
+ .single();
755
+ ----
756
+
757
+ With a `java.util.Optional` result:
758
+
759
+ [source,java,indent=0,subs="verbatim,quotes"]
760
+ ----
761
+ Optional<Actor> actor = this.jdbcClient.sql("select first_name, last_name from t_actor where id = ?",
762
+ .param(1212L);
763
+ .query((rs, rowNum) -> new Actor(rs.getString("first_name"), rs.getString("last_name")))
764
+ .optional();
765
+ ----
766
+
767
+ And for an update statement:
768
+
769
+ [source,java,indent=0,subs="verbatim,quotes"]
770
+ ----
771
+ this.jdbcClient.sql("insert into t_actor (first_name, last_name) values (?, ?)")
772
+ .param("Leonor").param("Watling");
773
+ .update();
774
+ ----
775
+
776
+ NOTE: `JdbcClient` is a flexible but simplified facade for JDBC query/update statements.
777
+ Advanced capabilities such as batch inserts and stored procedure calls typically require
778
+ extra customization: consider Spring's `SimpleJdbcInsert` and `SimpleJdbcCall` classes or
779
+ plain direct `JdbcTemplate` usage for any such capabilities not available on `JdbcClient`.
712
780
713
781
714
782
[[jdbc-SQLExceptionTranslator]]
0 commit comments