该包包含允许您访问的类 数据库以更面向对象的方式进行。例如,您可以运行查询 并将结果作为包含具有关系的业务对象的列表返回 映射到业务对象属性的列数据。您也可以运行存储 过程并运行 update、delete 和 insert 语句。org.springframework.jdbc.objectSpring中文文档

许多 Spring 开发人员认为,下面描述的各种 RDBMS 操作类 (StoredProcedure 类除外)可以经常 替换为直接呼叫。通常,编写 DAO 更简单 直接调用方法的方法(与 将查询封装为一个完整的类)。JdbcTemplateJdbcTemplateSpring中文文档

但是,如果您从使用 RDBMS 操作类中获得可衡量的价值, 应继续使用这些类。Spring中文文档

许多 Spring 开发人员认为,下面描述的各种 RDBMS 操作类 (StoredProcedure 类除外)可以经常 替换为直接呼叫。通常,编写 DAO 更简单 直接调用方法的方法(与 将查询封装为一个完整的类)。JdbcTemplateJdbcTemplateSpring中文文档

但是,如果您从使用 RDBMS 操作类中获得可衡量的价值, 应继续使用这些类。Spring中文文档

理解SqlQuery

SqlQuery是一个可重用的线程安全类,用于封装 SQL 查询。子 必须实现该方法以提供可以 通过遍历创建的 在执行查询期间。该类很少直接使用,因为 子类提供了更方便的实现 将行映射到 Java 类。其他扩展的实现是 和 。newRowMapper(..)RowMapperResultSetSqlQueryMappingSqlQuerySqlQueryMappingSqlQueryWithParametersUpdatableSqlQuerySpring中文文档

MappingSqlQuery

MappingSqlQuery是一个可重用的查询,其中具体子类必须实现 抽象方法将提供的每一行转换为 对象。以下示例显示了一个自定义查询,该查询映射了 与类实例的关系中的数据:mapRow(..)ResultSett_actorActorSpring中文文档

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")
	)
}

该类使用类型进行参数化扩展。构造函数 对于此客户查询,将 A 作为唯一参数。在这个 构造函数,你可以用 和 SQL 调用超类上的构造函数 应运行该操作以检索此查询的行。此 SQL 用于 创建一个 ,因此它可以包含任何参数的占位符 在执行过程中传入。您必须使用传入 .采用名称和 JDBC 类型 如 中所定义。定义所有参数后,可以调用该方法,以便可以准备语句并在以后运行。这个类是 thread-safe 编译后,所以,只要这些实例是在 DAO 创建时创建的 初始化后,它们可以保留为实例变量并重用。以下 示例演示如何定义这样的类:MappingSqlQueryActorDataSourceDataSourcePreparedStatementdeclareParameterSqlParameterSqlParameterjava.sql.Typescompile()Spring中文文档

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 的 that 作为 only 参数。由于我们只想返回一个对象,因此我们称之为便利性 方法,并作为参数。如果我们有一个返回 对象列表并采用其他参数,我们将使用其中一种方法,该方法采用作为 varargs 传入的参数值数组。以下 示例演示了这样的方法:idfindObjectidexecuteSpring中文文档

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 更新。与查询一样,更新对象是 可重用,并且与所有类一样,更新可以具有参数,并且是 在 SQL 中定义。此类提供了许多类似于查询对象方法的方法。这门课是具体的。它可以是 subclassed — 例如,添加自定义更新方法。 但是,您不必对类进行子类化,因为可以通过设置 SQL 和声明参数轻松对其进行参数化。 下面的示例创建名为 :SqlUpdateRdbmsOperationupdate(..)execute(..)SqlUpdateSqlUpdateexecuteSpring中文文档

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 对象抽象的超类 存储过程。StoredProcedureabstractSpring中文文档

继承的属性是 RDBMS 中存储过程的名称。sqlSpring中文文档

若要为类定义参数,可以使用 或 其子类。您必须在构造函数中指定参数名称和 SQL 类型, 如以下代码片段所示:StoredProcedureSqlParameterSpring中文文档

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.TypesSpring中文文档

第一行(带有 )声明 IN 参数。可以使用 IN 参数 对于存储过程调用和使用 和 的查询 子类(在了解 SqlQuery 中介绍)。SqlParameterSqlQuerySpring中文文档

第二行(带有 )声明要在 存储过程调用。还有一个 for 参数 (为过程提供值并返回值的参数)。SqlOutParameteroutSqlInOutParameterInOutinSpring中文文档

对于参数,除了名称和 SQL 类型外,还可以指定 数值数据的缩放比例或自定义数据库类型的类型名称。对于参数, 您可以提供 用于处理从游标返回的行的映射。 另一个选项是指定一个允许您定义自定义的选项 返回值的处理。inoutRowMapperREFSqlReturnTypeSpring中文文档

简单 DAO 的下一个示例使用 a 来调用函数 (),它随任何 Oracle 数据库一起提供。使用存储过程 功能,您必须创建一个扩展 .在这个 例如,该类是一个内部类。但是,如果需要重用 ,可以将其声明为顶级类。此示例没有输入 参数,但输出参数是使用类声明为日期类型的。该方法运行该过程并提取 从结果中返回日期。结果对每个声明都有一个条目 输出参数(在本例中,只有一个),方法是使用参数名称作为键。 下面的列表显示了我们的自定义 StoredProcedure 类:StoredProceduresysdate()StoredProcedureStoredProcedureStoredProcedureSqlOutParameterexecute()MapMapSpring中文文档

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 游标):StoredProcedureSpring中文文档

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(..)TitlesAndGenresStoredProcedureRowMapperRowMapperSpring中文文档

该类将 a 映射到中每一行的域对象 提供的 ,如下所示:TitleMapperResultSetTitleResultSetSpring中文文档

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 映射到中每一行的域对象 提供的 ,如下所示:GenreMapperResultSetGenreResultSetSpring中文文档

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"))
	}
}

将参数传递给具有一个或多个输入参数的存储过程 定义 在 RDBMS 中,您可以编写一个强类型方法,该方法将 委托给超类中的非类型化方法,如以下示例所示:execute(..)execute(Map)Spring中文文档

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))
}