该包包含允许您访问
数据库。例如,您可以运行查询
并将结果作为列表返回,其中包含具有关系
映射到业务对象属性的列数据。您也可以运行 stored
过程并运行 Update、Delete 和 Insert 语句。org.springframework.jdbc.object
| 
 许多 Spring 开发人员认为,下面描述的各种 RDBMS 操作类
( 但是,如果您通过使用 RDBMS 操作类获得可衡量的值, 您应该继续使用这些类。  | 
| 
 许多 Spring 开发人员认为,下面描述的各种 RDBMS 操作类
( 但是,如果您通过使用 RDBMS 操作类获得可衡量的值, 您应该继续使用这些类。  | 
理解SqlQuery
SqlQuery是封装 SQL 查询的可重用、线程安全的类。子
必须实现 method 以提供一个实例,该实例可以
为通过迭代创建的
在执行查询期间。该类很少直接使用,因为
子类为
将行映射到 Java 类。扩展的其他实现包括 和 。newRowMapper(..)RowMapperResultSetSqlQueryMappingSqlQuerySqlQueryMappingSqlQueryWithParametersUpdatableSqlQuery
用MappingSqlQuery
MappingSqlQuery是一个可重用的查询,其中具体子类必须实现
abstract 方法将提供的每一行转换为
object 指定类型。以下示例显示了一个自定义查询,该查询将
来自类实例的关系的数据:mapRow(..)ResultSett_actorActor
- 
Java
 - 
Kotlin
 
public class ActorMappingQuery extends MappingSqlQuery<Actor> {
	public ActorMappingQuery(DataSource ds) {
		super(ds, "select id, first_name, last_name from t_actor where id = ?");
		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;
	}
}
class ActorMappingQuery(ds: DataSource) : MappingSqlQuery<Actor>(ds, "select id, first_name, last_name from t_actor where id = ?") {
	init {
		declareParameter(SqlParameter("id", Types.INTEGER))
		compile()
	}
	override fun mapRow(rs: ResultSet, rowNumber: Int) = Actor(
			rs.getLong("id"),
			rs.getString("first_name"),
			rs.getString("last_name")
	)
}
类使用 type 扩展参数化。构造函数
对于此客户,查询将 A 作为唯一参数。在这个
构造函数,你可以使用 和 SQL 调用超类的构造函数
应该运行该 API 以检索此查询的行。此 SQL 用于
创建一个 ,以便它可以包含任何参数的占位符
在执行期间传入。您必须使用传入 .它需要一个 name,而 JDBC 类型
如 中所定义。定义所有参数后,您可以调用该方法,以便可以准备语句并在以后运行。这个类是
线程安全的,因此,只要这些实例是在 DAO
初始化后,它们可以保留为实例变量并可重用。以下内容
example 演示如何定义此类:MappingSqlQueryActorDataSourceDataSourcePreparedStatementdeclareParameterSqlParameterSqlParameterjava.sql.Typescompile()
- 
Java
 - 
Kotlin
 
private ActorMappingQuery actorMappingQuery;
@Autowired
public void setDataSource(DataSource dataSource) {
	this.actorMappingQuery = new ActorMappingQuery(dataSource);
}
public Actor getActor(Long id) {
	return actorMappingQuery.findObject(id);
}
private val actorMappingQuery = ActorMappingQuery(dataSource)
fun getActor(id: Long) = actorMappingQuery.findObject(id)
前面示例中的方法检索 actor,其中 的 作为
only 参数。由于我们只想返回一个对象,因此我们将 convenience
方法。如果我们有一个返回
list of objects 并采用额外的参数,我们将使用其中一种方法,该方法接受作为 varargs 传入的参数值数组。以下内容
example 显示了这样的方法:idfindObjectidexecute
- 
Java
 - 
Kotlin
 
public List<Actor> searchForActors(int age, String namePattern) {
	return actorSearchMappingQuery.execute(age, namePattern);
}
fun searchForActors(age: Int, namePattern: String) =
			actorSearchMappingQuery.execute(age, namePattern)
用SqlUpdate
该类封装了 SQL 更新。与查询一样,更新对象是
reuseable,并且与所有类一样,更新可以具有参数,并且是
在 SQL 中定义。此类提供了许多类似于 query 对象的方法的方法。类是具体的。可以是
subclassed — 例如,添加自定义更新方法。
但是,您不必对类进行子类化,因为可以通过设置 SQL 和声明参数轻松对其进行参数化。
以下示例创建一个名为 的自定义更新方法:SqlUpdateRdbmsOperationupdate(..)execute(..)SqlUpdateSqlUpdateexecute
- 
Java
 - 
Kotlin
 
import java.sql.Types;
import javax.sql.DataSource;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.object.SqlUpdate;
public class UpdateCreditRating extends SqlUpdate {
	public UpdateCreditRating(DataSource ds) {
		setDataSource(ds);
		setSql("update customer set credit_rating = ? where id = ?");
		declareParameter(new SqlParameter("creditRating", Types.NUMERIC));
		declareParameter(new SqlParameter("id", Types.NUMERIC));
		compile();
	}
	/**
	 * @param id for the Customer to be updated
	 * @param rating the new value for credit rating
	 * @return number of rows updated
	 */
	public int execute(int id, int rating) {
		return update(rating, id);
	}
}
import java.sql.Types
import javax.sql.DataSource
import org.springframework.jdbc.core.SqlParameter
import org.springframework.jdbc.object.SqlUpdate
class UpdateCreditRating(ds: DataSource) : SqlUpdate() {
	init {
		setDataSource(ds)
		sql = "update customer set credit_rating = ? where id = ?"
		declareParameter(SqlParameter("creditRating", Types.NUMERIC))
		declareParameter(SqlParameter("id", Types.NUMERIC))
		compile()
	}
	/**
	 * @param id for the Customer to be updated
	 * @param rating the new value for credit rating
	 * @return number of rows updated
	 */
	fun execute(id: Int, rating: Int): Int {
		return update(rating, id)
	}
}
用StoredProcedure
该类是 RDBMS 的对象抽象的超类
存储过程。StoredProcedureabstract
继承的属性是 RDBMS 中存储过程的名称。sql
要为类定义参数,可以使用 或 1
的子类。您必须在构造函数中指定参数名称和 SQL 类型。
如下面的代码片段所示:StoredProcedureSqlParameter
- 
Java
 - 
Kotlin
 
new SqlParameter("in_id", Types.NUMERIC),
new SqlOutParameter("out_first_name", Types.VARCHAR),
SqlParameter("in_id", Types.NUMERIC),
SqlOutParameter("out_first_name", Types.VARCHAR),
SQL 类型是使用常量指定的。java.sql.Types
第一行(带有 )声明 IN 参数。您可以使用 IN 参数
对于存储过程调用和使用 the 及其
子类(在 Understanding SqlQuery 中介绍)。SqlParameterSqlQuery
第二行(带有 )声明要在
stored procedure 调用。还有一个 for 参数
(为过程提供值并返回值的参数)。SqlOutParameteroutSqlInOutParameterInOutin
对于参数,除了名称和 SQL 类型之外,您还可以指定
数字数据的 scale 或自定义数据库类型的 type name。对于参数,
您可以提供 to handle 从游标返回的行的映射。
另一个选项是指定一个,允许您定义自定义
返回值的处理。inoutRowMapperREFSqlReturnType
下一个简单 DAO 示例使用 a 调用函数
(),它随任何 Oracle 数据库一起提供。使用存储过程
功能,您必须创建一个扩展 .在这个
example,该类是一个内部类。但是,如果需要重用 ,则可以将其声明为顶级类。此示例没有输入
参数,但输出参数使用类声明为日期类型。该方法运行该过程并提取
从 results 返回 Date 。结果对每个声明的
output 参数(在本例中,只有一个)使用参数名称作为键。
下面的清单显示了我们的自定义 StoredProcedure 类:StoredProceduresysdate()StoredProcedureStoredProcedureStoredProcedureSqlOutParameterexecute()MapMap
- 
Java
 - 
Kotlin
 
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 java.sql.Types
import java.util.Date
import java.util.Map
import javax.sql.DataSource
import org.springframework.jdbc.core.SqlOutParameter
import org.springframework.jdbc.object.StoredProcedure
class StoredProcedureDao(dataSource: DataSource) {
	private val SQL = "sysdate"
	private val getSysdate = GetSysdateProcedure(dataSource)
	val sysdate: Date
		get() = getSysdate.execute()
	private inner class GetSysdateProcedure(dataSource: DataSource) : StoredProcedure() {
		init {
			setDataSource(dataSource)
			isFunction = true
			sql = SQL
			declareParameter(SqlOutParameter("date", Types.DATE))
			compile()
		}
		fun execute(): Date {
			// the 'sysdate' sproc has no input parameters, so an empty Map is supplied...
			val results = execute(mutableMapOf<String, Any>())
			return results["date"] as Date
		}
	}
}
下面的 a 示例有两个输出参数(在本例中为
Oracle REF cursors):StoredProcedure
- 
Java
 - 
Kotlin
 
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import oracle.jdbc.OracleTypes;
import org.springframework.jdbc.core.SqlOutParameter;
import org.springframework.jdbc.object.StoredProcedure;
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 java.util.HashMap
import javax.sql.DataSource
import oracle.jdbc.OracleTypes
import org.springframework.jdbc.core.SqlOutParameter
import org.springframework.jdbc.object.StoredProcedure
class TitlesAndGenresStoredProcedure(dataSource: DataSource) : StoredProcedure(dataSource, SPROC_NAME) {
	companion object {
		private const val SPROC_NAME = "AllTitlesAndGenres"
	}
	init {
		declareParameter(SqlOutParameter("titles", OracleTypes.CURSOR, TitleMapper()))
		declareParameter(SqlOutParameter("genres", OracleTypes.CURSOR, GenreMapper()))
		compile()
	}
	fun execute(): Map<String, Any> {
		// again, this sproc has no input parameters, so an empty Map is supplied
		return super.execute(HashMap<String, Any>())
	}
}
请注意
构造函数中使用的是传递的实现实例。这是一种非常方便和强大的重用现有
功能性。接下来的两个示例提供了两种实现的代码。declareParameter(..)TitlesAndGenresStoredProcedureRowMapperRowMapper
该类将 a 映射到 中每一行的域对象
提供的 ,如下所示:TitleMapperResultSetTitleResultSet
- 
Java
 - 
Kotlin
 
import java.sql.ResultSet;
import java.sql.SQLException;
import com.foo.domain.Title;
import org.springframework.jdbc.core.RowMapper;
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 java.sql.ResultSet
import com.foo.domain.Title
import org.springframework.jdbc.core.RowMapper
class TitleMapper : RowMapper<Title> {
	override fun mapRow(rs: ResultSet, rowNum: Int) =
			Title(rs.getLong("id"), rs.getString("name"))
}
该类将 a 映射到 中每一行的域对象
提供的 ,如下所示:GenreMapperResultSetGenreResultSet
- 
Java
 - 
Kotlin
 
import java.sql.ResultSet;
import java.sql.SQLException;
import com.foo.domain.Genre;
import org.springframework.jdbc.core.RowMapper;
public final class GenreMapper implements RowMapper<Genre> {
	public Genre mapRow(ResultSet rs, int rowNum) throws SQLException {
		return new Genre(rs.getString("name"));
	}
}
import java.sql.ResultSet
import com.foo.domain.Genre
import org.springframework.jdbc.core.RowMapper
class GenreMapper : RowMapper<Genre> {
	override fun mapRow(rs: ResultSet, rowNum: Int): Genre {
		return Genre(rs.getString("name"))
	}
}
将参数传递给其
定义,您可以编写一个强类型方法,该方法将
delegate 分配给超类中的非类型化方法,如下例所示:execute(..)execute(Map)
- 
Java
 - 
Kotlin
 
import java.sql.Types;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import oracle.jdbc.OracleTypes;
import org.springframework.jdbc.core.SqlOutParameter;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.object.StoredProcedure;
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);
	}
}
import java.sql.Types
import java.util.Date
import javax.sql.DataSource
import oracle.jdbc.OracleTypes
import org.springframework.jdbc.core.SqlOutParameter
import org.springframework.jdbc.core.SqlParameter
import org.springframework.jdbc.object.StoredProcedure
class TitlesAfterDateStoredProcedure(dataSource: DataSource) : StoredProcedure(dataSource, SPROC_NAME) {
	companion object {
		private const val SPROC_NAME = "TitlesAfterDate"
		private const val CUTOFF_DATE_PARAM = "cutoffDate"
	}
	init {
		declareParameter(SqlParameter(CUTOFF_DATE_PARAM, Types.DATE))
		declareParameter(SqlOutParameter("titles", OracleTypes.CURSOR, TitleMapper()))
		compile()
	}
	fun execute(cutoffDate: Date) = super.execute(
			mapOf<String, Any>(CUTOFF_DATE_PARAM to cutoffDate))
}