奋斗的机器人 · Tableau 和 JDBC - Tableau· 6 天前 · |
含蓄的火锅 · Java 8 上的 SQL Server ...· 4 天前 · |
爱热闹的充电器 · springboot2.0配置多数据源出错H ...· 2 天前 · |
深情的毛豆 · springboot2.0配置多数据源出错H ...· 2 天前 · |
调皮的草稿纸 · 会议通知:第一届生物数据资源学术会议暨中国生 ...· 1 周前 · |
谦逊的水煮肉 · JTextArea (Java 2 ...· 4 周前 · |
想出家的柠檬 · Installing Apache Ant· 1 月前 · |
飘逸的四季豆 · 咸阳陕建渭水朝阳_陕建渭水朝阳户型图_地址_ ...· 4 月前 · |
跑龙套的水煮鱼 · 实况手游安卓系统补丁安装教程_手机游戏热门视频· 5 月前 · |
jdbctemplate jdbc |
https://docs.spring.io/spring-framework/docs/3.0.x/spring-framework-reference/html/jdbc.html |
爽快的大蒜
5 月前 |
The Spring Framework takes care of all the low-level details that can make JDBC such a tedious API to develop with.
Note | |
---|---|
Spring 3.0 updates all of the following approaches with Java 5 support such as generics and varargs. |
The
org.springframework.jdbc.core
package
contains the
JdbcTemplate
class and its various
callback interfaces, plus a variety of related classes. A subpackage
named
org.springframework.jdbc.core.simple
contains
the
SimpleJdbcTemplate
class and the related
SimpleJdbcInsert
and
SimpleJdbcCall
classes. Another subpackage named
org.springframework.jdbc.core.namedparam
contains the
NamedParameterJdbcTemplate
class and the related
support classes. See
Section 12.2, “Using the JDBC core classes to control basic JDBC processing and
error handling”
,
Section 12.4, “JDBC batch operations”
, and
Section 12.5, “Simplifying JDBC operations with the SimpleJdbc classes”
The
org.springframework.jdbc.datasource
package
contains a utility class for easy
DataSource
access, and various simple
DataSource
implementations that can be
used for testing and running unmodified JDBC code outside of a Java EE
container. A subpackage named
org.springfamework.jdbc.datasource.embedded
provides
support for creating in-memory database instances using Java database
engines such as HSQL and H2. See
Section 12.3, “Controlling database connections”
and
Section 12.8, “Embedded database support”
The
org.springframework.jdbc.object
package
contains classes that represent RDBMS queries, updates, and stored
procedures as thread safe, reusable objects. See
Section 12.6, “Modeling JDBC operations as Java objects”
.This approach is modeled by JDO, although of
course objects returned by queries are “
disconnected
” from
the database. This higher level of JDBC abstraction depends on the
lower-level abstraction in the
org.springframework.jdbc.core
package.
The
org.springframework.jdbc.support
package provides
SQLException
translation functionality and some
utility classes. Exceptions thrown during JDBC processing are translated
to exceptions defined in the
org.springframework.dao
package. This means that code using the Spring JDBC abstraction layer
does not need to implement JDBC or RDBMS-specific error handling. All
translated exceptions are unchecked, which gives you the option of
catching the exceptions from which you can recover while allowing other
exceptions to be propagated to the caller. See
Section 12.2.4, “SQLExceptionTranslator”
.
Note | |
---|---|
The
|
Here is a simple query for getting the number of rows in a relation:
int rowCount = this.jdbcTemplate.queryForInt("select count(*) from t_actor");
A simple query using a bind variable:
int countOfActorsNamedJoe = this.jdbcTemplate.queryForInt( "select count(*) from t_actor where first_name = ?", "Joe");
String lastName = this.jdbcTemplate.queryForObject( "select last_name from t_actor where id = ?", new Object[]{1212L}, String.class);
Querying and populating a single domain object:
Actor actor = this.jdbcTemplate.queryForObject( "select first_name, last_name from t_actor where id = ?", new Object[]{1212L}, new RowMapper<Actor>() { public Actor mapRow(ResultSet rs, int rowNum) throws SQLException { Actor actor = new Actor(); actor.setFirstName(rs.getString("first_name")); actor.setLastName(rs.getString("last_name")); return actor;
Querying and populating a number of domain objects:
List<Actor> actors = this.jdbcTemplate.query( "select first_name, last_name from t_actor", new RowMapper<Actor>() { public Actor mapRow(ResultSet rs, int rowNum) throws SQLException { Actor actor = new Actor(); actor.setFirstName(rs.getString("first_name")); actor.setLastName(rs.getString("last_name")); return actor;
public List<Actor> findAllActors() { return this.jdbcTemplate.query( "select first_name, last_name from t_actor", new ActorMapper()); private static final class ActorMapper implements RowMapper<Actor> { public Actor mapRow(ResultSet rs, int rowNum) throws SQLException { Actor actor = new Actor(); actor.setFirstName(rs.getString("first_name")); actor.setLastName(rs.getString("last_name")); return actor; }
this.jdbcTemplate.update( "insert into t_actor (first_name, last_name) values (?, ?)", "Leonor", "Watling");
this.jdbcTemplate.update( "update t_actor set = ? where id = ?", "Banjo", 5276L);
this.jdbcTemplate.update( "delete from actor where id = ?", Long.valueOf(actorId));
this.jdbcTemplate.execute("create table mytable (id integer, name varchar(100))");
The following example invokes a simple stored procedure. More sophisticated stored procedure support is covered later .
this.jdbcTemplate.update( "call SUPPORT.REFRESH_ACTORS_SUMMARY(?)", Long.valueOf(unionId));
A common practice when using the
JdbcTemplate
class (and the associated
SimpleJdbcTemplate
and
NamedParameterJdbcTemplate
classes) is to configure a
DataSource
in your Spring configuration file, and then dependency-inject that
shared
DataSource
bean into your DAO
classes; the
JdbcTemplate
is created in the
setter for the
DataSource
. This leads
to DAOs that look in part like the following:
public class JdbcCorporateEventDao implements CorporateEventDao { private JdbcTemplate jdbcTemplate; public void setDataSource(DataSource dataSource) { this.jdbcTemplate = new JdbcTemplate(dataSource); // JDBC-backed implementations of the methods on the CorporateEventDao follow... }
The corresponding configuration might look like this.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean id="corporateEventDao" class="com.example.JdbcCorporateEventDao"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <context:property-placeholder location="jdbc.properties"/> </beans>
An alternative to explicit configuration is to use
component-scanning and annotation support for dependency injection. In
this case you annotate the class with
@Repository
(which makes it a candidate
for component-scanning) and annotate the
DataSource
setter method with
@Autowired
.
@Repository public class JdbcCorporateEventDao implements CorporateEventDao { private JdbcTemplate jdbcTemplate; @Autowired public void setDataSource(DataSource dataSource) { this.jdbcTemplate = new JdbcTemplate(dataSource); // JDBC-backed implementations of the methods on the CorporateEventDao follow... }
The corresponding XML configuration file would look like the following:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- Scans within the base package of the application for @Components to configure as beans --> <context:component-scan base-package="org.springframework.docs.test" /> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <context:property-placeholder location="jdbc.properties"/> </beans>
If you are using Spring's
JdbcDaoSupport
class, and your various
JDBC-backed DAO classes extend from it, then your sub-class inherits a
setDataSource(..)
method from the
JdbcDaoSupport
class. You
can choose whether to inherit from this class. The
JdbcDaoSupport
class is provided as a
convenience only.
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 time you
want to execute SQL. Once configured, a
JdbcTemplate
instance is threadsafe. You may
want multiple
JdbcTemplate
instances if your
application accesses multiple databases, which requires multiple
DataSources
, and subsequently multiple
differently configured
JdbcTemplates
.
// some JDBC-backed DAO class... private NamedParameterJdbcTemplate namedParameterJdbcTemplate; public void setDataSource(DataSource dataSource) { this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource); public int countOfActorsByFirstName(String firstName) { String sql = "select count(*) from T_ACTOR where first_name = :first_name"; SqlParameterSource namedParameters = new MapSqlParameterSource("first_name", firstName); return namedParameterJdbcTemplate.queryForInt(sql, namedParameters); }
The following example shows the use of the
Map
-based style.
// some JDBC-backed DAO class... private NamedParameterJdbcTemplate namedParameterJdbcTemplate; public void setDataSource(DataSource dataSource) { this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource); public int countOfActorsByFirstName(String firstName) { String sql = "select count(*) from T_ACTOR where first_name = :first_name"; Map namedParameters = Collections.singletonMap("first_name", firstName); return this.namedParameterJdbcTemplate.queryForInt(sql, namedParameters); }
Another
SqlParameterSource
implementation is the
BeanPropertySqlParameterSource
class. This class
wraps an arbitrary JavaBean (that is, an instance of a class that
adheres to
the JavaBean
conventions
), and uses the properties of the wrapped JavaBean as
the source of named parameter values.
public class Actor { private Long id; private String firstName; private String lastName; public String getFirstName() { return this.firstName; public String getLastName() { return this.lastName; public Long getId() { return this.id; // setters omitted... }
// some JDBC-backed DAO class... private NamedParameterJdbcTemplate namedParameterJdbcTemplate; public void setDataSource(DataSource dataSource) { this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource); public int countOfActors(Actor exampleActor) { // 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"; SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(exampleActor); return this.namedParameterJdbcTemplate.queryForInt(sql, namedParameters); }
Remember that the
NamedParameterJdbcTemplate
class
wraps
a classic
JdbcTemplate
template; if you need access to the wrapped
JdbcTemplate
instance to access functionality
only present in the
JdbcTemplate
class, you can
use the
getJdbcOperations()
method to access
the wrapped
JdbcTemplate
through the
JdbcOperations
interface.
See also
Section 12.2.1.2, “JdbcTemplate best practices”
for
guidelines on using the
NamedParameterJdbcTemplate
class in the context
of an application.
Note | |
---|---|
In Spring 3.0, the original
|
// classic JdbcTemplate-style... private JdbcTemplate jdbcTemplate; public void setDataSource(DataSource dataSource) { this.jdbcTemplate = new JdbcTemplate(dataSource); public Actor findActor(String specialty, int age) { String sql = "select id, first_name, last_name from T_ACTOR" + " where specialty = ? and age = ?"; RowMapper<Actor> mapper = new RowMapper<Actor>() { public Actor mapRow(ResultSet rs, int rowNum) throws SQLException { Actor actor = new Actor(); actor.setId(rs.getLong("id")); actor.setFirstName(rs.getString("first_name")); actor.setLastName(rs.getString("last_name")); return actor; // notice the wrapping up of the argumenta in an array return (Actor) jdbcTemplate.queryForObject(sql, new Object[] {specialty, age}, mapper); }
Here is the same method, with the
SimpleJdbcTemplate
.
// SimpleJdbcTemplate-style... private SimpleJdbcTemplate simpleJdbcTemplate; public void setDataSource(DataSource dataSource) { this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); public Actor findActor(String specialty, int age) { String sql = "select id, first_name, last_name from T_ACTOR" + " where specialty = ? and age = ?"; RowMapper<Actor> mapper = new RowMapper<Actor>() { public Actor mapRow(ResultSet rs, int rowNum) throws SQLException { Actor actor = new Actor(); actor.setId(rs.getLong("id")); actor.setFirstName(rs.getString("first_name")); actor.setLastName(rs.getString("last_name")); return actor; // notice the use of varargs since the parameter values now come // after the RowMapper parameter return this.simpleJdbcTemplate.queryForObject(sql, mapper, specialty, age); }
See
Section 12.2.1.2, “JdbcTemplate best practices”
for guidelines on
how to use the
SimpleJdbcTemplate
class in the
context of an application.
Note | |
---|---|
The
|
The
SQLErrorCodeSQLExceptionTranslator
applies matching rules in the following sequence:
Note | |
---|---|
The
|
You can extend
SQLErrorCodeSQLExceptionTranslator:
public class CustomSQLErrorCodesTranslator extends SQLErrorCodeSQLExceptionTranslator { protected DataAccessException customTranslate(String task, String sql, SQLException sqlex) { if (sqlex.getErrorCode() == -12345) { return new DeadlockLoserDataAccessException(task, sqlex); return null; }
private JdbcTemplate jdbcTemoplate; public void setDataSource(DataSource dataSource) { // create a JdbcTemplate and set data source this.jdbcTemplate = new JdbcTemplate(); this.jdbcTemplate.setDataSource(dataSource); // create a custom translator and set the DataSource for the default translation lookup CustomSQLErrorCodesTranslator tr = new CustomSQLErrorCodesTranslator(); tr.setDataSource(dataSource); this.jdbcTemplate.setExceptionTranslator(tr); public void updateShippingCharge(long orderId, long pct) { // use the prepared JdbcTemplate for this update this.jdbcTemplate.update( "update orders" + " set shipping_charge = shipping_charge * ? / 100" + " where id = ?" pct, orderId); }
import javax.sql.DataSource; import org.springframework.jdbc.core.JdbcTemplate; public class RunAQuery { private JdbcTemplate jdbcTemplate; public void setDataSource(DataSource dataSource) { this.jdbcTemplate = new JdbcTemplate(dataSource); public int getCount() { return this.jdbcTemplate.queryForInt("select count(*) from mytable"); public String getName() { return (String) this.jdbcTemplate.queryForObject("select name from mytable", String.class); public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; }
private JdbcTemplate jdbcTemplate; public void setDataSource(DataSource dataSource) { this.jdbcTemplate = new JdbcTemplate(dataSource); public List<Map<String, Object>> getList() { return this.jdbcTemplate.queryForList("select * from mytable"); }
The list returned would look something like this:
[{name=Bob, id=1}, {name=Mary, id=2}]
Note | |
---|---|
Only use the
|
DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("org.hsqldb.jdbcDriver"); dataSource.setUrl("jdbc:hsqldb:hsql://localhost:"); dataSource.setUsername("sa"); dataSource.setPassword("");
Here is the corresponding XML configuration:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <context:property-placeholder location="jdbc.properties"/>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <context:property-placeholder location="jdbc.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="${jdbc.driverClassName}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <context:property-placeholder location="jdbc.properties"/>
Note | |
---|---|
It is rarely desirable to use this class, except when already
existing code that must be called and passed a standard JDBC
|
(See the
TransactionAwareDataSourceProxy
Javadocs for more
details.)
This example shows a batch update using named parameters:
public class JdbcActorDao implements ActorDao { private SimpleJdbcTemplate simpleJdbcTemplate; public void setDataSource(DataSource dataSource) { this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); public int[] batchUpdate(final List<Actor> actors) { SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(actors.toArray()); int[] updateCounts = simpleJdbcTemplate.batchUpdate( "update t_actor set first_name = :firstName, last_name = :lastName where id = :id", batch); return updateCounts; // ... additional methods }
The same example using classic JDBC "?" placeholders:
public class JdbcActorDao implements ActorDao { private SimpleJdbcTemplate simpleJdbcTemplate; public void setDataSource(DataSource dataSource) { this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); public int[] batchUpdate(final List<Actor> actors) { List<Object[]> batch = new ArrayList<Object[]>(); for (Actor actor : actors) { Object[] values = new Object[] { actor.getFirstName(), actor.getLastName(), actor.getId()}; batch.add(values); int[] updateCounts = simpleJdbcTemplate.batchUpdate( "update t_actor set first_name = ?, last_name = ? where id = ?", batch); return updateCounts; // ... additional methods }
public class JdbcActorDao implements ActorDao { private SimpleJdbcTemplate simpleJdbcTemplate; private SimpleJdbcInsert insertActor; public void setDataSource(DataSource dataSource) { this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); this.insertActor = new SimpleJdbcInsert(dataSource) .withTableName("t_actor") .usingGeneratedKeyColumns("id"); public void add(Actor actor) { SqlParameterSource parameters = new BeanPropertySqlParameterSource(actor); Number newId = insertActor.executeAndReturnKey(parameters); actor.setId(newId.longValue()); // ... additional methods }
public class JdbcActorDao implements ActorDao { private SimpleJdbcTemplate simpleJdbcTemplate; private SimpleJdbcInsert insertActor; public void setDataSource(DataSource dataSource) { this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); this.insertActor = new SimpleJdbcInsert(dataSource) .withTableName("t_actor") .usingGeneratedKeyColumns("id"); public void add(Actor actor) { SqlParameterSource parameters = new MapSqlParameterSource() .addValue("first_name", actor.getFirstName()) .addValue("last_name", actor.getLastName()); Number newId = insertActor.executeAndReturnKey(parameters); actor.setId(newId.longValue()); // ... additional methods }
CREATE PROCEDURE read_actor ( IN in_id INTEGER, OUT out_first_name VARCHAR(100), OUT out_last_name VARCHAR(100), OUT out_birth_date DATE) BEGIN SELECT first_name, last_name, birth_date INTO out_first_name, out_last_name, out_birth_date FROM t_actor where id = in_id; END;
public class JdbcActorDao implements ActorDao { private SimpleJdbcTemplate simpleJdbcTemplate; private SimpleJdbcCall procReadActor; public void setDataSource(DataSource dataSource) { this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); this.procReadActor = new SimpleJdbcCall(dataSource) .withProcedureName("read_actor"); public Actor readActor(Long id) { SqlParameterSource in = new MapSqlParameterSource() .addValue("in_id", id); Map out = procReadActor.execute(in); Actor actor = new Actor(); actor.setId(id); actor.setFirstName((String) out.get("out_first_name")); actor.setLastName((String) out.get("out_last_name")); actor.setBirthDate((Date) out.get("out_birth_date")); return actor; // ... additional methods }
public class JdbcActorDao implements ActorDao { private SimpleJdbcCall procReadActor; public void setDataSource(DataSource dataSource) { JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); jdbcTemplate.setResultsMapCaseInsensitive(true); this.procReadActor = new SimpleJdbcCall(jdbcTemplate) .withProcedureName("read_actor"); // ... additional methods }
Note | |
---|---|
Explicit declarations are necessary if the database you use is not a Spring-supported database. Currently Spring supports metadata lookup of stored procedure calls for the following databases: Apache Derby, DB2, MySQL, Microsoft SQL Server, Oracle, and Sybase. We also support metadata lookup of stored functions for: MySQL, Microsoft SQL Server, and Oracle. |
public class JdbcActorDao implements ActorDao { private SimpleJdbcCall procReadActor; public void setDataSource(DataSource dataSource) { JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); jdbcTemplate.setResultsMapCaseInsensitive(true); this.procReadActor = new SimpleJdbcCall(jdbcTemplate) .withProcedureName("read_actor") .withoutProcedureColumnMetaDataAccess() .useInParameterNames("in_id") .declareParameters( new SqlParameter("in_id", Types.NUMERIC), new SqlOutParameter("out_first_name", Types.VARCHAR), new SqlOutParameter("out_last_name", Types.VARCHAR), new SqlOutParameter("out_birth_date", Types.DATE) // ... additional methods }
To define a parameter for the SimpleJdbc classes and also for the
RDBMS operations classes, covered in
Section 12.6, “Modeling JDBC operations as Java objects”
,
use an
SqlParameter
or one of its subclasses. You
typically specify the parameter name and SQL type in the constructor.
The SQL type is specified using the
java.sql.Types
constants. We have already seen
declarations like:
new SqlParameter("in_id", Types.NUMERIC), new SqlOutParameter("out_first_name", Types.VARCHAR),
The first line with the
SqlParameter
declares an IN parameter. IN parameters can be used for both stored
procedure calls and for queries using the
SqlQuery
and its subclasses covered in the
following section.
The second line with the
SqlOutParameter
declares an
out
parameter to be used in a stored procedure
call. There is also an
SqlInOutParameter
for
InOut
parameters, parameters that provide an
IN
value to the procedure and that also return a
value.
Note | |
---|---|
Only parameters declared as
|
For IN parameters, in addition to the name and the SQL type, you
can specify a scale for numeric data or a type name for custom database
types. For
out
parameters, you can provide a
RowMapper
to handle mapping of rows returned from
a
REF
cursor. Another option is to specify an
SqlReturnType
that provides an opportunity to
define customized handling of the return values.
CREATE FUNCTION get_actor_name (in_id INTEGER) RETURNS VARCHAR(200) READS SQL DATA BEGIN DECLARE out_name VARCHAR(200); SELECT concat(first_name, ' ', last_name) INTO out_name FROM t_actor where id = in_id; RETURN out_name; END;
To call this function we again create a
SimpleJdbcCall
in the initialization
method.
public class JdbcActorDao implements ActorDao { private SimpleJdbcTemplate simpleJdbcTemplate; private SimpleJdbcCall funcGetActorName; public void setDataSource(DataSource dataSource) { this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); jdbcTemplate.setResultsMapCaseInsensitive(true); this.funcGetActorName = new SimpleJdbcCall(jdbcTemplate) .withFunctionName("get_actor_name"); public String getActorName(Long id) { SqlParameterSource in = new MapSqlParameterSource() .addValue("in_id", id); String name = funcGetActorName.executeFunction(String.class, in); return name; // ... additional methods }
The execute method used
returns a
String
containing the return value from
the function call.
CREATE PROCEDURE read_all_actors() BEGIN SELECT a.id, a.first_name, a.last_name, a.birth_date FROM t_actor a; END;
public class JdbcActorDao implements ActorDao { private SimpleJdbcTemplate simpleJdbcTemplate; private SimpleJdbcCall procReadAllActors; public void setDataSource(DataSource dataSource) { this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); jdbcTemplate.setResultsMapCaseInsensitive(true); this.procReadAllActors = new SimpleJdbcCall(jdbcTemplate) .withProcedureName("read_all_actors") .returningResultSet("actors", ParameterizedBeanPropertyRowMapper.newInstance(Actor.class)); public List getActorsList() { Map m = procReadAllActors.execute(new HashMap<String, Object>(0)); return (List) m.get("actors"); // ... additional methods }
Note | |
---|---|
Many Spring developers believe that the various RDBMS operation
classes described below (with the exception of the
However, if you are getting measurable value from using the RDBMS operation classes, continue using these classes. |
public class ActorMappingQuery extends MappingSqlQuery<Actor> { public ActorMappingQuery(DataSource ds) { super(ds, "select id, first_name, last_name from t_actor where id = ?"); super.declareParameter(new SqlParameter("id", Types.INTEGER)); compile(); @Override protected Actor mapRow(ResultSet rs, int rowNumber) throws SQLException { Actor actor = new Actor(); actor.setId(rs.getLong("id")); actor.setFirstName(rs.getString("first_name")); actor.setLastName(rs.getString("last_name")); return actor; }
private ActorMappingQuery actorMappingQuery; @Autowired public void setDataSource(DataSource dataSource) { this.actorMappingQuery = new ActorMappingQuery(dataSource); public Customer getCustomer(Long id) { return actorMappingQuery.findObject(id); }
public List<Actor> searchForActors(int age, String namePattern) { List<Actor> actors = actorSearchMappingQuery.execute(age, namePattern); return actors; }
The inherited
sql
property will be the name of
the stored procedure in the RDBMS.
new SqlParameter("in_id", Types.NUMERIC), new SqlOutParameter("out_first_name", Types.VARCHAR),
import java.sql.Types; import java.util.Date; import java.util.HashMap; import java.util.Map; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.SqlOutParameter; import org.springframework.jdbc.object.StoredProcedure; public class StoredProcedureDao { private GetSysdateProcedure getSysdate; @Autowired public void init(DataSource dataSource) { this.getSysdate = new GetSysdateProcedure(dataSource); public Date getSysdate() { return getSysdate.execute(); private class GetSysdateProcedure extends StoredProcedure { private static final String SQL = "sysdate"; public GetSysdateProcedure(DataSource dataSource) { setDataSource(dataSource); setFunction(true); setSql(SQL); declareParameter(new SqlOutParameter("date", Types.DATE)); compile(); public Date execute() { // the 'sysdate' sproc has no input parameters, so an empty Map is supplied... Map<String, Object> results = execute(new HashMap<String, Object>()); Date sysdate = (Date) results.get("date"); return sysdate; }
import oracle.jdbc.OracleTypes; import org.springframework.jdbc.core.SqlOutParameter; import org.springframework.jdbc.object.StoredProcedure; import javax.sql.DataSource; import java.util.HashMap; import java.util.Map; public class TitlesAndGenresStoredProcedure extends StoredProcedure { private static final String SPROC_NAME = "AllTitlesAndGenres"; public TitlesAndGenresStoredProcedure(DataSource dataSource) { super(dataSource, SPROC_NAME); declareParameter(new SqlOutParameter("titles", OracleTypes.CURSOR, new TitleMapper())); declareParameter(new SqlOutParameter("genres", OracleTypes.CURSOR, new GenreMapper())); compile(); public Map<String, Object> execute() { // again, this sproc has no input parameters, so an empty Map is supplied return super.execute(new HashMap<String, Object>()); }
import org.springframework.jdbc.core.RowMapper; import java.sql.ResultSet; import java.sql.SQLException; import com.foo.domain.Title; public final class TitleMapper implements RowMapper<Title> { public Title mapRow(ResultSet rs, int rowNum) throws SQLException { Title title = new Title(); title.setId(rs.getLong("id")); title.setName(rs.getString("name")); return title; }
import org.springframework.jdbc.core.RowMapper; import java.sql.ResultSet; import java.sql.SQLException; import com.foo.domain.Genre; public final class GenreMapper implements RowMapper<Genre> { public Genre mapRow(ResultSet rs, int rowNum) throws SQLException { return new Genre(rs.getString("name")); }
import oracle.jdbc.OracleTypes; import org.springframework.jdbc.core.SqlOutParameter; import org.springframework.jdbc.core.SqlParameter; import org.springframework.jdbc.object.StoredProcedure; import javax.sql.DataSource; import java.sql.Types; import java.util.Date; import java.util.HashMap; import java.util.Map; public class TitlesAfterDateStoredProcedure extends StoredProcedure { private static final String SPROC_NAME = "TitlesAfterDate"; private static final String CUTOFF_DATE_PARAM = "cutoffDate"; public TitlesAfterDateStoredProcedure(DataSource dataSource) { super(dataSource, SPROC_NAME); declareParameter(new SqlParameter(CUTOFF_DATE_PARAM, Types.DATE); declareParameter(new SqlOutParameter("titles", OracleTypes.CURSOR, new TitleMapper())); compile(); public Map<String, Object> execute(Date cutoffDate) { Map<String, Object> inputs = new HashMap<String, Object>(); inputs.put(CUTOFF_DATE_PARAM, cutoffDate); return super.execute(inputs); }
The
LobCreator/LobHandler
provides the
following support for LOB input and output:
final File blobIn = new File("spring2004.jpg"); final InputStream blobIs = new FileInputStream(blobIn); final File clobIn = new File("large.txt"); final InputStream clobIs = new FileInputStream(clobIn); final InputStreamReader clobReader = new InputStreamReader(clobIs); jdbcTemplate.execute( "INSERT INTO lob_table (id, a_clob, a_blob) VALUES (?, ?, ?)", new AbstractLobCreatingPreparedStatementCallback(lobHandler) { protected void setValues(PreparedStatement ps, LobCreator lobCreator) throws SQLException { ps.setLong(1, 1L); lobCreator.setClobAsCharacterStream(ps, 2, clobReader, (int)clobIn.length()); lobCreator.setBlobAsBinaryStream(ps, 3, blobIs, (int)blobIn.length()); blobIs.close(); clobReader.close();
|
Pass in the lobHandler that in this example is a plain
|
|
Using the method
|
|
Using the method
|
List<Map<String, Object>> l = jdbcTemplate.query("select id, a_clob, a_blob from lob_table", new RowMapper<Map<String, Object>>() { public Map<String, Object> mapRow(ResultSet rs, int i) throws SQLException { Map<String, Object> results = new HashMap<String, Object>(); String clobText = lobHandler.getClobAsString(rs, "a_clob"); results.put("CLOB", clobText); byte[] blobBytes = lobHandler.getBlobAsBytes(rs, "a_blob"); results.put("BLOB", blobBytes); return results;
|
Using the method
|
|
Using the method
|
Note | |
---|---|
Be careful when passing in many values. The JDBC standard does
not guarantee that you can use more than 100 values for an
|
final TestItem - new TestItem(123L, "A test item", new SimpleDateFormat("yyyy-M-d").parse("2010-12-31");); declareParameter(new SqlOutParameter("item", OracleTypes.STRUCT, "ITEM_TYPE", new SqlReturnType() { public Object getTypeValue(CallableStatement cs, int colIndx, int sqlType, String typeName) throws SQLException { STRUCT struct = (STRUCT)cs.getObject(colIndx); Object[] attr = struct.getAttributes(); TestItem item = new TestItem(); item.setId(((Number) attr[0]).longValue()); item.setDescription((String)attr[1]); item.setExpirationDate((java.util.Date)attr[2]); return item; }));
final TestItem - new TestItem(123L, "A test item", new SimpleDateFormat("yyyy-M-d").parse("2010-12-31");); SqlTypeValue value = new AbstractSqlTypeValue() { protected Object createTypeValue(Connection conn, int sqlType, String typeName) throws SQLException { StructDescriptor itemDescriptor = new StructDescriptor(typeName, conn); Struct item = new STRUCT(itemDescriptor, conn, new Object[] { testItem.getId(), testItem.getDescription(), new java.sql.Date(testItem.getExpirationDate().getTime()) return item; };
final Long[] ids = new Long[] {1L, 2L}; SqlTypeValue value = new AbstractSqlTypeValue() { protected Object createTypeValue(Connection conn, int sqlType, String typeName) throws SQLException { ArrayDescriptor arrayDescriptor = new ArrayDescriptor(typeName, conn); ARRAY idArray = new ARRAY(arrayDescriptor, conn, ids); return idArray; };
The
org.springframework.jdbc.datasource.embedded
package provides support for embedded Java database engines. Support for
HSQL
,
H2
, and
Derby
is provided natively. You
can also use an extensible API to plug in new embedded database types and
DataSource
implementations.
Spring JDBC embedded database support can be extended in two ways:
You are encouraged to contribute back extensions to the Spring community at jira.springframework.org .
<jdbc:initialize-database data-source="dataSource"> <jdbc:script location="classpath:com/foo/sql/db-schema.sql"/> <jdbc:script location="classpath:com/foo/sql/db-test-data.sql"/> </jdbc:initialize-database>
<jdbc:initialize-database data-source="dataSource" enabled="#{systemProperties.INITIALIZE_DATABASE}"> <jdbc:script location="..."/> </jdbc:initialize-database>
<jdbc:initialize-database data-source="dataSource" ignore-failures="DROPS"> <jdbc:script location="..."/> </jdbc:initialize-database>
奋斗的机器人 · Tableau 和 JDBC - Tableau 6 天前 |
爱热闹的充电器 · springboot2.0配置多数据源出错HikariPool-1 - jdbcUrl is required with driverClassName._13405677的技术博客_ 2 天前 |
深情的毛豆 · springboot2.0配置多数据源出错HikariPool-1 - jdbcUrl is required with driverClassName._13405677的技术博客_ 2 天前 |
想出家的柠檬 · Installing Apache Ant 1 月前 |
跑龙套的水煮鱼 · 实况手游安卓系统补丁安装教程_手机游戏热门视频 5 月前 |