Migrate to Asciidoctor Tabs

This commit is contained in:
Rob Winch
2023-04-20 16:21:36 -05:00
committed by rstoyanchev
parent 71154fd16b
commit 39146f9066
243 changed files with 7124 additions and 1779 deletions

View File

@@ -17,8 +17,11 @@ the prepared statement. This method is called the number of times that you
specified in the `getBatchSize` call. The following example updates the `t_actor` table
based on entries in a list, and the entire list is used as the batch:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public class JdbcActorDao implements ActorDao {
@@ -47,8 +50,10 @@ based on entries in a list, and the entire list is used as the batch:
// ... additional methods
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
class JdbcActorDao(dataSource: DataSource) : ActorDao {
@@ -71,6 +76,7 @@ based on entries in a list, and the entire list is used as the batch:
// ... additional methods
}
----
======
If you process a stream of updates or reading from a file, you might have a
preferred batch size, but the last batch might not have that number of entries. In this
@@ -94,8 +100,11 @@ in an array of bean-style objects (with getter methods corresponding to paramete
The following example shows a batch update using named parameters:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public class JdbcActorDao implements ActorDao {
@@ -114,8 +123,10 @@ The following example shows a batch update using named parameters:
// ... additional methods
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
class JdbcActorDao(dataSource: DataSource) : ActorDao {
@@ -130,6 +141,7 @@ The following example shows a batch update using named parameters:
// ... additional methods
}
----
======
For an SQL statement that uses the classic `?` placeholders, you pass in a list
containing an object array with the update values. This object array must have one entry
@@ -139,8 +151,11 @@ defined in the SQL statement.
The following example is the same as the preceding example, except that it uses classic
JDBC `?` placeholders:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public class JdbcActorDao implements ActorDao {
@@ -165,8 +180,10 @@ JDBC `?` placeholders:
// ... additional methods
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
class JdbcActorDao(dataSource: DataSource) : ActorDao {
@@ -184,6 +201,7 @@ JDBC `?` placeholders:
// ... additional methods
}
----
======
All of the batch update methods that we described earlier return an `int` array
containing the number of affected rows for each batch entry. This count is reported by
@@ -223,8 +241,11 @@ update calls into batches of the size specified.
The following example shows a batch update that uses a batch size of 100:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public class JdbcActorDao implements ActorDao {
@@ -250,8 +271,10 @@ The following example shows a batch update that uses a batch size of 100:
// ... additional methods
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
class JdbcActorDao(dataSource: DataSource) : ActorDao {
@@ -270,6 +293,7 @@ The following example shows a batch update that uses a batch size of 100:
// ... additional methods
}
----
======
The batch update method for this call returns an array of `int` arrays that contains an
array entry for each batch with an array of the number of affected rows for each update.

View File

@@ -48,8 +48,11 @@ To configure a `DriverManagerDataSource`:
The following example shows how to configure a `DriverManagerDataSource` in Java:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
@@ -57,8 +60,10 @@ The following example shows how to configure a `DriverManagerDataSource` in Java
dataSource.setUsername("sa");
dataSource.setPassword("");
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val dataSource = DriverManagerDataSource().apply {
setDriverClassName("org.hsqldb.jdbcDriver")
@@ -67,6 +72,7 @@ The following example shows how to configure a `DriverManagerDataSource` in Java
password = ""
}
----
======
The following example shows the corresponding XML configuration:

View File

@@ -57,54 +57,75 @@ See the attendant {api-spring-framework}/jdbc/core/JdbcTemplate.html[javadoc] fo
The following query gets the number of rows in a relation:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
int rowCount = this.jdbcTemplate.queryForObject("select count(*) from t_actor", Integer.class);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val rowCount = jdbcTemplate.queryForObject<Int>("select count(*) from t_actor")!!
----
======
The following query uses a bind variable:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
int countOfActorsNamedJoe = this.jdbcTemplate.queryForObject(
"select count(*) from t_actor where first_name = ?", Integer.class, "Joe");
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val countOfActorsNamedJoe = jdbcTemplate.queryForObject<Int>(
"select count(*) from t_actor where first_name = ?", arrayOf("Joe"))!!
----
======
The following query looks for a `String`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
String lastName = this.jdbcTemplate.queryForObject(
"select last_name from t_actor where id = ?",
String.class, 1212L);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val lastName = this.jdbcTemplate.queryForObject<String>(
"select last_name from t_actor where id = ?",
arrayOf(1212L))!!
----
======
The following query finds and populates a single domain object:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
Actor actor = jdbcTemplate.queryForObject(
"select first_name, last_name from t_actor where id = ?",
@@ -116,8 +137,10 @@ The following query finds and populates a single domain object:
},
1212L);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val actor = jdbcTemplate.queryForObject(
"select first_name, last_name from t_actor where id = ?",
@@ -125,11 +148,15 @@ The following query finds and populates a single domain object:
Actor(rs.getString("first_name"), rs.getString("last_name"))
}
----
======
The following query finds and populates a list of domain objects:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
List<Actor> actors = this.jdbcTemplate.query(
"select first_name, last_name from t_actor",
@@ -140,20 +167,26 @@ The following query finds and populates a list of domain objects:
return actor;
});
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val actors = jdbcTemplate.query("select first_name, last_name from t_actor") { rs, _ ->
Actor(rs.getString("first_name"), rs.getString("last_name"))
----
======
If the last two snippets of code actually existed in the same application, it would make
sense to remove the duplication present in the two `RowMapper` lambda expressions and
extract them out into a single field that could then be referenced by DAO methods as needed.
For example, it may be better to write the preceding code snippet as follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
private final RowMapper<Actor> actorRowMapper = (resultSet, rowNum) -> {
Actor actor = new Actor();
@@ -166,8 +199,10 @@ For example, it may be better to write the preceding code snippet as follows:
return this.jdbcTemplate.query("select first_name, last_name from t_actor", actorRowMapper);
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val actorMapper = RowMapper<Actor> { rs: ResultSet, rowNum: Int ->
Actor(rs.getString("first_name"), rs.getString("last_name"))
@@ -177,6 +212,7 @@ For example, it may be better to write the preceding code snippet as follows:
return jdbcTemplate.query("select first_name, last_name from t_actor", actorMapper)
}
----
======
[[jdbc-JdbcTemplate-examples-update]]
=== Updating (`INSERT`, `UPDATE`, and `DELETE`) with `JdbcTemplate`
@@ -186,52 +222,70 @@ Parameter values are usually provided as variable arguments or, alternatively, a
The following example inserts a new entry:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
this.jdbcTemplate.update(
"insert into t_actor (first_name, last_name) values (?, ?)",
"Leonor", "Watling");
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
jdbcTemplate.update(
"insert into t_actor (first_name, last_name) values (?, ?)",
"Leonor", "Watling")
----
======
The following example updates an existing entry:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
this.jdbcTemplate.update(
"update t_actor set last_name = ? where id = ?",
"Banjo", 5276L);
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
jdbcTemplate.update(
"update t_actor set last_name = ? where id = ?",
"Banjo", 5276L)
----
======
The following example deletes an entry:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
this.jdbcTemplate.update(
"delete from t_actor where id = ?",
Long.valueOf(actorId));
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
jdbcTemplate.update("delete from t_actor where id = ?", actorId.toLong())
----
======
[[jdbc-JdbcTemplate-examples-other]]
=== Other `JdbcTemplate` Operations
@@ -241,33 +295,45 @@ method is often used for DDL statements. It is heavily overloaded with variants
callback interfaces, binding variable arrays, and so on. The following example creates a
table:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
this.jdbcTemplate.execute("create table mytable (id integer, name varchar(100))");
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
jdbcTemplate.execute("create table mytable (id integer, name varchar(100))")
----
======
The following example invokes a stored procedure:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
this.jdbcTemplate.update(
"call SUPPORT.REFRESH_ACTORS_SUMMARY(?)",
Long.valueOf(unionId));
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
jdbcTemplate.update(
"call SUPPORT.REFRESH_ACTORS_SUMMARY(?)",
unionId.toLong())
----
======
More sophisticated stored procedure support is xref:data-access/jdbc/object.adoc#jdbc-StoredProcedure[covered later].
@@ -288,8 +354,11 @@ that shared `DataSource` bean into your DAO classes. The `JdbcTemplate` is creat
the setter for the `DataSource`. This leads to DAOs that resemble the following:
--
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public class JdbcCorporateEventDao implements CorporateEventDao {
@@ -302,8 +371,10 @@ the setter for the `DataSource`. This leads to DAOs that resemble the following:
// JDBC-backed implementations of the methods on the CorporateEventDao follow...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
class JdbcCorporateEventDao(dataSource: DataSource) : CorporateEventDao {
@@ -312,6 +383,7 @@ the setter for the `DataSource`. This leads to DAOs that resemble the following:
// JDBC-backed implementations of the methods on the CorporateEventDao follow...
}
----
======
--
The following example shows the corresponding XML configuration:
@@ -350,8 +422,11 @@ support for dependency injection. In this case, you can annotate the class with
method with `@Autowired`. The following example shows how to do so:
--
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Repository // <1>
public class JdbcCorporateEventDao implements CorporateEventDao {
@@ -366,6 +441,7 @@ method with `@Autowired`. The following example shows how to do so:
// JDBC-backed implementations of the methods on the CorporateEventDao follow...
}
----
======
<1> Annotate the class with `@Repository`.
<2> Annotate the `DataSource` setter method with `@Autowired`.
<3> Create a new `JdbcTemplate` with the `DataSource`.
@@ -440,8 +516,11 @@ section describes only those areas of the `NamedParameterJdbcTemplate` class tha
from the `JdbcTemplate` itself -- namely, programming JDBC statements by using named
parameters. The following example shows how to use `NamedParameterJdbcTemplate`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// some JDBC-backed DAO class...
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
@@ -460,8 +539,9 @@ parameters. The following example shows how to use `NamedParameterJdbcTemplate`:
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
private val namedParameterJdbcTemplate = NamedParameterJdbcTemplate(dataSource)
@@ -471,6 +551,7 @@ parameters. The following example shows how to use `NamedParameterJdbcTemplate`:
return namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Int::class.java)!!
}
----
======
Notice the use of the named parameter notation in the value assigned to the `sql`
variable and the corresponding value that is plugged into the `namedParameters`
@@ -483,8 +564,11 @@ methods exposed by the `NamedParameterJdbcOperations` and implemented by the
The following example shows the use of the `Map`-based style:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// some JDBC-backed DAO class...
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
@@ -502,8 +586,10 @@ The following example shows the use of the `Map`-based style:
return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class);
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// some JDBC-backed DAO class...
private val namedParameterJdbcTemplate = NamedParameterJdbcTemplate(dataSource)
@@ -514,6 +600,7 @@ The following example shows the use of the `Map`-based style:
return namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Int::class.java)!!
}
----
======
One nice feature related to the `NamedParameterJdbcTemplate` (and existing in the same
Java package) is the `SqlParameterSource` interface. You have already seen an example of
@@ -531,8 +618,11 @@ of named parameter values.
The following example shows a typical JavaBean:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public class Actor {
@@ -556,17 +646,23 @@ The following example shows a typical JavaBean:
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
data class Actor(val id: Long, val firstName: String, val lastName: String)
----
======
The following example uses a `NamedParameterJdbcTemplate` to return the count of the
members of the class shown in the preceding example:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
// some JDBC-backed DAO class...
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
@@ -585,8 +681,10 @@ members of the class shown in the preceding example:
return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class);
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// some JDBC-backed DAO class...
private val namedParameterJdbcTemplate = NamedParameterJdbcTemplate(dataSource)
@@ -600,6 +698,7 @@ members of the class shown in the preceding example:
return namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Int::class.java)!!
}
----
======
Remember that the `NamedParameterJdbcTemplate` class wraps a classic `JdbcTemplate`
template. If you need access to the wrapped `JdbcTemplate` instance to access
@@ -651,8 +750,11 @@ name from the database metadata of the database in use.
You can extend `SQLErrorCodeSQLExceptionTranslator`, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public class CustomSQLErrorCodesTranslator extends SQLErrorCodeSQLExceptionTranslator {
@@ -664,8 +766,10 @@ You can extend `SQLErrorCodeSQLExceptionTranslator`, as the following example sh
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
class CustomSQLErrorCodesTranslator : SQLErrorCodeSQLExceptionTranslator() {
@@ -677,6 +781,7 @@ You can extend `SQLErrorCodeSQLExceptionTranslator`, as the following example sh
}
}
----
======
In the preceding example, the specific error code (`-12345`) is translated, while other errors are
left to be translated by the default translator implementation. To use this custom
@@ -685,8 +790,11 @@ translator, you must pass it to the `JdbcTemplate` through the method
processing where this translator is needed. The following example shows how you can use this custom
translator:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
private JdbcTemplate jdbcTemplate;
@@ -710,8 +818,10 @@ translator:
" where id = ?", pct, orderId);
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
// create a JdbcTemplate and set data source
private val jdbcTemplate = JdbcTemplate(dataSource).apply {
@@ -728,6 +838,7 @@ translator:
" where id = ?", pct, orderId)
}
----
======
The custom translator is passed a data source in order to look up the error codes in
`sql-error-codes.xml`.
@@ -741,8 +852,11 @@ Running an SQL statement requires very little code. You need a `DataSource` and
`JdbcTemplate`. The following example shows what you need to include for a minimal but
fully functional class that creates a new table:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -760,8 +874,10 @@ fully functional class that creates a new table:
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
import javax.sql.DataSource
import org.springframework.jdbc.core.JdbcTemplate
@@ -775,6 +891,7 @@ fully functional class that creates a new table:
}
}
----
======
[[jdbc-statements-querying]]
@@ -786,8 +903,11 @@ Java class that is passed in as an argument. If the type conversion is invalid,
`InvalidDataAccessApiUsageException` is thrown. The following example contains two
query methods, one for an `int` and one that queries for a `String`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -809,8 +929,10 @@ query methods, one for an `int` and one that queries for a `String`:
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
import javax.sql.DataSource
import org.springframework.jdbc.core.JdbcTemplate
@@ -826,6 +948,7 @@ class RunAQuery(dataSource: DataSource) {
get() = jdbcTemplate.queryForObject("select name from mytable")
}
----
======
In addition to the single result query methods, several methods return a list with an
entry for each row that the query returned. The most generic method is `queryForList(..)`,
@@ -833,8 +956,11 @@ which returns a `List` where each element is a `Map` containing one entry for ea
using the column name as the key. If you add a method to the preceding example to retrieve a
list of all the rows, it might be as follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
private JdbcTemplate jdbcTemplate;
@@ -846,8 +972,10 @@ list of all the rows, it might be as follows:
return this.jdbcTemplate.queryForList("select * from mytable");
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
private val jdbcTemplate = JdbcTemplate(dataSource)
@@ -855,6 +983,7 @@ list of all the rows, it might be as follows:
return jdbcTemplate.queryForList("select * from mytable")
}
----
======
The returned list would resemble the following:
@@ -869,8 +998,11 @@ The returned list would resemble the following:
The following example updates a column for a certain primary key:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
@@ -888,8 +1020,10 @@ The following example updates a column for a certain primary key:
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
import javax.sql.DataSource
import org.springframework.jdbc.core.JdbcTemplate
@@ -903,6 +1037,7 @@ The following example updates a column for a certain primary key:
}
}
----
======
In the preceding example,
an SQL statement has placeholders for row parameters. You can pass the parameter values
@@ -922,8 +1057,11 @@ update. There is no standard single way to create an appropriate `PreparedStatem
(which explains why the method signature is the way it is). The following example works
on Oracle but may not work on other platforms:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
final String INSERT_SQL = "insert into my_test (name) values(?)";
final String name = "Rob";
@@ -937,8 +1075,10 @@ on Oracle but may not work on other platforms:
// keyHolder.getKey() now contains the generated key
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val INSERT_SQL = "insert into my_test (name) values(?)"
val name = "Rob"
@@ -950,6 +1090,7 @@ on Oracle but may not work on other platforms:
// keyHolder.getKey() now contains the generated key
----
======

View File

@@ -44,8 +44,11 @@ The `EmbeddedDatabaseBuilder` class provides a fluent API for constructing an em
database programmatically. You can use this when you need to create an embedded database in a
stand-alone environment or in a stand-alone integration test, as in the following example:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
EmbeddedDatabase db = new EmbeddedDatabaseBuilder()
.generateUniqueName(true)
@@ -60,8 +63,10 @@ stand-alone environment or in a stand-alone integration test, as in the followin
db.shutdown()
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val db = EmbeddedDatabaseBuilder()
.generateUniqueName(true)
@@ -76,6 +81,7 @@ stand-alone environment or in a stand-alone integration test, as in the followin
db.shutdown()
----
======
See the {api-spring-framework}/jdbc/datasource/embedded/EmbeddedDatabaseBuilder.html[javadoc for `EmbeddedDatabaseBuilder`]
for further details on all supported options.
@@ -83,8 +89,11 @@ for further details on all supported options.
You can also use the `EmbeddedDatabaseBuilder` to create an embedded database by using Java
configuration, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
@Configuration
public class DataSourceConfig {
@@ -102,8 +111,10 @@ configuration, as the following example shows:
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
@Configuration
class DataSourceConfig {
@@ -121,6 +132,7 @@ configuration, as the following example shows:
}
}
----
======
[[jdbc-embedded-database-types]]
@@ -168,8 +180,11 @@ configuring the embedded database as a bean in the Spring `ApplicationContext` a
in xref:data-access/jdbc/embedded-database-support.adoc#jdbc-embedded-database-xml[Creating an Embedded Database by Using Spring XML] and xref:data-access/jdbc/embedded-database-support.adoc#jdbc-embedded-database-java[Creating an Embedded Database Programmatically]. The following listing
shows the test template:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public class DataAccessIntegrationTestTemplate {
@@ -198,8 +213,10 @@ shows the test template:
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
class DataAccessIntegrationTestTemplate {
@@ -227,6 +244,7 @@ shows the test template:
}
}
----
======
[[jdbc-embedded-database-unique-names]]

View File

@@ -40,8 +40,11 @@ abstract `mapRow(..)` method to convert each row of the supplied `ResultSet` int
object of the type specified. The following example shows a custom query that maps the
data from the `t_actor` relation to an instance of the `Actor` class:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public class ActorMappingQuery extends MappingSqlQuery<Actor> {
@@ -61,8 +64,10 @@ data from the `t_actor` relation to an instance of the `Actor` class:
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
class ActorMappingQuery(ds: DataSource) : MappingSqlQuery<Actor>(ds, "select id, first_name, last_name from t_actor where id = ?") {
@@ -79,6 +84,7 @@ data from the `t_actor` relation to an instance of the `Actor` class:
}
----
======
The class extends `MappingSqlQuery` parameterized with the `Actor` type. The constructor
for this customer query takes a `DataSource` as the only parameter. In this
@@ -93,8 +99,11 @@ thread-safe after it is compiled, so, as long as these instances are created whe
is initialized, they can be kept as instance variables and be reused. The following
example shows how to define such a class:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
private ActorMappingQuery actorMappingQuery;
@@ -107,13 +116,16 @@ example shows how to define such a class:
return actorMappingQuery.findObject(id);
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
private val actorMappingQuery = ActorMappingQuery(dataSource)
fun getCustomer(id: Long) = actorMappingQuery.findObject(id)
----
======
The method in the preceding example retrieves the customer with the `id` that is passed in as the
only parameter. Since we want only one object to be returned, we call the `findObject` convenience
@@ -122,19 +134,25 @@ list of objects and took additional parameters, we would use one of the `execute
methods that takes an array of parameter values passed in as varargs. The following
example shows such a method:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public List<Actor> searchForActors(int age, String namePattern) {
return actorSearchMappingQuery.execute(age, namePattern);
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
fun searchForActors(age: Int, namePattern: String) =
actorSearchMappingQuery.execute(age, namePattern)
----
======
[[jdbc-SqlUpdate]]
@@ -149,8 +167,11 @@ However, you do not have to subclass the `SqlUpdate`
class, since it can easily be parameterized by setting SQL and declaring parameters.
The following example creates a custom update method named `execute`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
import java.sql.Types;
import javax.sql.DataSource;
@@ -177,8 +198,10 @@ The following example creates a custom update method named `execute`:
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
import java.sql.Types
import javax.sql.DataSource
@@ -205,6 +228,7 @@ The following example creates a custom update method named `execute`:
}
}
----
======
[[jdbc-StoredProcedure]]
@@ -219,18 +243,24 @@ To define a parameter for the `StoredProcedure` class, you can use an `SqlParame
of its subclasses. You must specify the parameter name and SQL type in the constructor,
as the following code snippet shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
new SqlParameter("in_id", Types.NUMERIC),
new SqlOutParameter("out_first_name", Types.VARCHAR),
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
SqlParameter("in_id", Types.NUMERIC),
SqlOutParameter("out_first_name", Types.VARCHAR),
----
======
The SQL type is specified using the `java.sql.Types` constants.
@@ -259,8 +289,11 @@ returned date from the results `Map`. The results `Map` has an entry for each de
output parameter (in this case, only one) by using the parameter name as the key.
The following listing shows our custom StoredProcedure class:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
import java.sql.Types;
import java.util.Date;
@@ -306,8 +339,10 @@ The following listing shows our custom StoredProcedure class:
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
import java.sql.Types
import java.util.Date
@@ -343,12 +378,16 @@ The following listing shows our custom StoredProcedure class:
}
}
----
======
The following example of a `StoredProcedure` has two output parameters (in this case,
Oracle REF cursors):
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
import java.util.HashMap;
import java.util.Map;
@@ -374,8 +413,10 @@ Oracle REF cursors):
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
import java.util.HashMap
import javax.sql.DataSource
@@ -401,6 +442,7 @@ Oracle REF cursors):
}
}
----
======
Notice how the overloaded variants of the `declareParameter(..)` method that have been
used in the `TitlesAndGenresStoredProcedure` constructor are passed `RowMapper`
@@ -410,8 +452,11 @@ functionality. The next two examples provide code for the two `RowMapper` implem
The `TitleMapper` class maps a `ResultSet` to a `Title` domain object for each row in
the supplied `ResultSet`, as follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -428,8 +473,10 @@ the supplied `ResultSet`, as follows:
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
import java.sql.ResultSet
import com.foo.domain.Title
@@ -441,12 +488,16 @@ the supplied `ResultSet`, as follows:
Title(rs.getLong("id"), rs.getString("name"))
}
----
======
The `GenreMapper` class maps a `ResultSet` to a `Genre` domain object for each row in
the supplied `ResultSet`, as follows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -460,8 +511,10 @@ the supplied `ResultSet`, as follows:
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
import java.sql.ResultSet
import com.foo.domain.Genre
@@ -474,13 +527,17 @@ the supplied `ResultSet`, as follows:
}
}
----
======
To pass parameters to a stored procedure that has one or more input parameters in its
definition in the RDBMS, you can code a strongly typed `execute(..)` method that would
delegate to the untyped `execute(Map)` method in the superclass, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
import java.sql.Types;
import java.util.Date;
@@ -511,8 +568,10 @@ delegate to the untyped `execute(Map)` method in the superclass, as the followin
}
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
import java.sql.Types
import java.util.Date
@@ -539,6 +598,7 @@ delegate to the untyped `execute(Map)` method in the superclass, as the followin
mapOf<String, Any>(CUTOFF_DATE_PARAM to cutoffDate))
}
----
======

View File

@@ -63,8 +63,11 @@ dependency injection.
The following example shows how to create and insert a BLOB:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
final File blobIn = new File("spring2004.jpg");
final InputStream blobIs = new FileInputStream(blobIn);
@@ -86,6 +89,7 @@ The following example shows how to create and insert a BLOB:
blobIs.close();
clobReader.close();
----
======
<1> Pass in the `lobHandler` that (in this example) is a plain `DefaultLobHandler`.
<2> Using the method `setClobAsCharacterStream` to pass in the contents of the CLOB.
<3> Using the method `setBlobAsBinaryStream` to pass in the contents of the BLOB.
@@ -134,8 +138,11 @@ Now it is time to read the LOB data from the database. Again, you use a `JdbcTem
with the same instance variable `lobHandler` and a reference to a `DefaultLobHandler`.
The following example shows how to do so:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
List<Map<String, Object>> l = jdbcTemplate.query("select id, a_clob, a_blob from lob_table",
new RowMapper<Map<String, Object>>() {
@@ -149,6 +156,7 @@ The following example shows how to do so:
}
});
----
======
<1> Using the method `getClobAsString` to retrieve the contents of the CLOB.
<2> Using the method `getBlobAsBytes` to retrieve the contents of the BLOB.
@@ -203,8 +211,11 @@ implemented. This interface is used as part of the declaration of an `SqlOutPara
The following example shows returning the value of an Oracle `STRUCT` object of the user
declared type `ITEM_TYPE`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public class TestItemStoredProcedure extends StoredProcedure {
@@ -223,8 +234,10 @@ declared type `ITEM_TYPE`:
// ...
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
class TestItemStoredProcedure(dataSource: DataSource) : StoredProcedure() {
@@ -239,6 +252,7 @@ declared type `ITEM_TYPE`:
}
}
----
======
You can use `SqlTypeValue` to pass the value of a Java object (such as `TestItem`) to a
stored procedure. The `SqlTypeValue` interface has a single method (named
@@ -246,8 +260,11 @@ stored procedure. The `SqlTypeValue` interface has a single method (named
can use it to create database-specific objects, such as `StructDescriptor` instances
or `ArrayDescriptor` instances. The following example creates a `StructDescriptor` instance:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
final TestItem testItem = new TestItem(123L, "A test item",
new SimpleDateFormat("yyyy-M-d").parse("2010-12-31"));
@@ -265,8 +282,10 @@ or `ArrayDescriptor` instances. The following example creates a `StructDescripto
}
};
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
val (id, description, expirationDate) = TestItem(123L, "A test item",
SimpleDateFormat("yyyy-M-d").parse("2010-12-31"))
@@ -279,6 +298,7 @@ or `ArrayDescriptor` instances. The following example creates a `StructDescripto
}
}
----
======
You can now add this `SqlTypeValue` to the `Map` that contains the input parameters for the
`execute` call of the stored procedure.
@@ -288,8 +308,11 @@ procedure. Oracle has its own internal `ARRAY` class that must be used in this c
you can use the `SqlTypeValue` to create an instance of the Oracle `ARRAY` and populate
it with values from the Java `ARRAY`, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
final Long[] ids = new Long[] {1L, 2L};
@@ -301,8 +324,10 @@ it with values from the Java `ARRAY`, as the following example shows:
}
};
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
class TestItemStoredProcedure(dataSource: DataSource) : StoredProcedure() {
@@ -317,6 +342,7 @@ it with values from the Java `ARRAY`, as the following example shows:
}
}
----
======

View File

@@ -19,8 +19,11 @@ Configuration methods for this class follow the `fluid` style that returns the i
of the `SimpleJdbcInsert`, which lets you chain all configuration methods. The following
example uses only one configuration method (we show examples of multiple methods later):
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public class JdbcActorDao implements ActorDao {
@@ -41,8 +44,10 @@ example uses only one configuration method (we show examples of multiple methods
// ... additional methods
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
class JdbcActorDao(dataSource: DataSource) : ActorDao {
@@ -59,6 +64,7 @@ example uses only one configuration method (we show examples of multiple methods
// ... additional methods
}
----
======
The `execute` method used here takes a plain `java.util.Map` as its only parameter. The
important thing to note here is that the keys used for the `Map` must match the column
@@ -75,8 +81,11 @@ the `SimpleJdbcInsert`, in addition to specifying the table name, it specifies t
of the generated key column with the `usingGeneratedKeyColumns` method. The following
listing shows how it works:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public class JdbcActorDao implements ActorDao {
@@ -99,8 +108,10 @@ listing shows how it works:
// ... additional methods
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
class JdbcActorDao(dataSource: DataSource) : ActorDao {
@@ -118,6 +129,7 @@ listing shows how it works:
// ... additional methods
}
----
======
The main difference when you run the insert by using this second approach is that you do not
add the `id` to the `Map`, and you call the `executeAndReturnKey` method. This returns a
@@ -134,8 +146,11 @@ use a `KeyHolder` that is returned from the `executeAndReturnKeyHolder` method.
You can limit the columns for an insert by specifying a list of column names with the
`usingColumns` method, as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public class JdbcActorDao implements ActorDao {
@@ -159,8 +174,10 @@ You can limit the columns for an insert by specifying a list of column names wit
// ... additional methods
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
class JdbcActorDao(dataSource: DataSource) : ActorDao {
@@ -180,6 +197,7 @@ You can limit the columns for an insert by specifying a list of column names wit
// ... additional methods
}
----
======
The execution of the insert is the same as if you had relied on the metadata to determine
which columns to use.
@@ -195,8 +213,11 @@ which is a very convenient class if you have a JavaBean-compliant class that con
your values. It uses the corresponding getter method to extract the parameter
values. The following example shows how to use `BeanPropertySqlParameterSource`:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public class JdbcActorDao implements ActorDao {
@@ -217,8 +238,10 @@ values. The following example shows how to use `BeanPropertySqlParameterSource`:
// ... additional methods
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
class JdbcActorDao(dataSource: DataSource) : ActorDao {
@@ -235,12 +258,16 @@ values. The following example shows how to use `BeanPropertySqlParameterSource`:
// ... additional methods
}
----
======
Another option is the `MapSqlParameterSource` that resembles a `Map` but provides a more
convenient `addValue` method that can be chained. The following example shows how to use it:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public class JdbcActorDao implements ActorDao {
@@ -263,8 +290,10 @@ convenient `addValue` method that can be chained. The following example shows ho
// ... additional methods
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
class JdbcActorDao(dataSource: DataSource) : ActorDao {
@@ -283,6 +312,7 @@ convenient `addValue` method that can be chained. The following example shows ho
// ... additional methods
}
----
======
As you can see, the configuration is the same. Only the executing code has to change to
use these alternative input classes.
@@ -325,8 +355,11 @@ The following example of a `SimpleJdbcCall` configuration uses the preceding sto
procedure (the only configuration option, in addition to the `DataSource`, is the name
of the stored procedure):
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public class JdbcActorDao implements ActorDao {
@@ -352,8 +385,10 @@ of the stored procedure):
// ... additional methods
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
class JdbcActorDao(dataSource: DataSource) : ActorDao {
@@ -374,6 +409,7 @@ of the stored procedure):
// ... additional methods
}
----
======
The code you write for the execution of the call involves creating an `SqlParameterSource`
containing the IN parameter. You must match the name provided for the input value
@@ -397,8 +433,11 @@ To do the latter, you can create your own `JdbcTemplate` and set the `setResults
property to `true`. Then you can pass this customized `JdbcTemplate` instance into
the constructor of your `SimpleJdbcCall`. The following example shows this configuration:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public class JdbcActorDao implements ActorDao {
@@ -414,8 +453,10 @@ the constructor of your `SimpleJdbcCall`. The following example shows this confi
// ... additional methods
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
class JdbcActorDao(dataSource: DataSource) : ActorDao {
@@ -426,6 +467,7 @@ the constructor of your `SimpleJdbcCall`. The following example shows this confi
// ... additional methods
}
----
======
By taking this action, you avoid conflicts in the case used for the names of your
returned `out` parameters.
@@ -456,8 +498,11 @@ of IN parameter names to include for a given signature.
The following example shows a fully declared procedure call and uses the information from
the preceding example:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public class JdbcActorDao implements ActorDao {
@@ -481,8 +526,10 @@ the preceding example:
// ... additional methods
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
class JdbcActorDao(dataSource: DataSource) : ActorDao {
@@ -501,6 +548,7 @@ the preceding example:
// ... additional methods
}
----
======
The execution and end results of the two examples are the same. The second example specifies all
details explicitly rather than relying on metadata.
@@ -515,18 +563,24 @@ To do so, you typically specify the parameter name and SQL type in the construct
is specified by using the `java.sql.Types` constants. Earlier in this chapter, we saw declarations
similar to the following:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
new SqlParameter("in_id", Types.NUMERIC),
new SqlOutParameter("out_first_name", Types.VARCHAR),
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
SqlParameter("in_id", Types.NUMERIC),
SqlOutParameter("out_first_name", Types.VARCHAR),
----
======
The first line with the `SqlParameter` declares an IN parameter. You can use IN parameters
for both stored procedure calls and for queries by using the `SqlQuery` and its
@@ -578,8 +632,11 @@ that returns an actor's full name:
To call this function, we again create a `SimpleJdbcCall` in the initialization method,
as the following example shows:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public class JdbcActorDao implements ActorDao {
@@ -602,8 +659,10 @@ as the following example shows:
// ... additional methods
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
class JdbcActorDao(dataSource: DataSource) : ActorDao {
@@ -621,6 +680,7 @@ as the following example shows:
// ... additional methods
}
----
======
The `executeFunction` method used returns a `String` that contains the return value from the
function call.
@@ -656,8 +716,11 @@ to map follows the JavaBean rules, you can use a `BeanPropertyRowMapper` that is
passing in the required class to map to in the `newInstance` method.
The following example shows how to do so:
[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
.Java
----
public class JdbcActorDao implements ActorDao {
@@ -680,8 +743,10 @@ The following example shows how to do so:
// ... additional methods
}
----
Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
.Kotlin
----
class JdbcActorDao(dataSource: DataSource) : ActorDao {
@@ -699,6 +764,7 @@ The following example shows how to do so:
// ... additional methods
}
----
======
The `execute` call passes in an empty `Map`, because this call does not take any parameters.
The list of actors is then retrieved from the results map and returned to the caller.