3.8参数和数据值处理的常见问题
Spring Framework的JDBC支持提供的不同方法中存在参数和数据值的常见问题。本节介绍如何解决它们。
3.8.1 提供参数的SQL类型信息
通常,Spring根据传入的参数类型确定参数的SQL类型。可以在设置参数值时显式提供要使用的SQL类型。有时需要正确设置NULL值。
您可以通过几种方式提供SQL类型信息:
JdbcTemplate的许多更新和查询方法都采用int数组形式的附加参数。该数组用于通过使用java.sql.Types类中的常量值来指示相应参数的SQL类型。为每个参数提供一个条目。
您可以使用SqlParameterValue类包装需要此附加信息的参数值。为此,请为每个值创建一个新实例,然后在构造函数中传入SQL类型和参数值。您还可以为数字值提供可选的比例参数。
对于使用命名参数的方法,可以使用SqlParameterSource类,BeanPropertySqlParameterSource或MapSqlParameterSource。它们都具有用于为任何命名参数值注册SQL类型的方法。
3.8.2 处理BLOB和CLOB对象
您可以在数据库中存储图像,其他二进制数据和大块文本。这些大对象称为二进制数据的BLOB(二进制大型对象),而字符数据称为CLOB(字符大型对象)。在Spring中,可以直接使用JdbcTemplate来处理这些大对象,也可以使用RDBMS Objects和SimpleJdbc类提供的更高抽象来处理这些大对象。所有这些方法都使用LobHandler接口的实现来对LOB(大对象)数据进行实际管理。 LobHandler通过getLobCreator方法提供对LobCreator类的访问,该方法用于创建要插入的新LOB对象。
LobCreator和LobHandler为LOB输入和输出提供以下支持:
BLOB
byte []:getBlobAsBytes和setBlobAsBytes
InputStream:getBlobAsBinaryStream和setBlobAsBinaryStream
CLOB
String:getClobAsString和setClobAsString
InputStream:getClobAsAsciiStream和setClobAsAsciiStream
Reader:getClobAsCharacterStream和setClobAsCharacterStream
下一个示例显示了如何创建和插入BLOB。稍后,我们展示如何从数据库中读取回它。
本示例使用JdbcTemplate和AbstractLobCreatingPreparedStatementCallback的实现。它实现了一种方法setValues。此方法提供了一个LobCreator,我们可以使用它来设置SQL插入语句中的LOB列的值。
对于此示例,我们假设存在一个变量lobHandler,该变量已经设置为DefaultLobHandler的实例。通常,您可以通过依赖注入来设置此值。
以下示例显示如何创建和插入BLOB:
如果在从DefaultLobHandler.getLobCreator()返回的LobCreator上调用setBlobAsBinaryStream,setClobAsAsciiStream或setClobAsCharacterStream方法,则可以选择为contentLength参数指定负值。 如果指定的内容长度为负,则DefaultLobHandler将使用set-stream方法的JDBC 4.0变体,而不使用length参数。 否则,它将指定的长度传递给驱动程序。
请参阅有关JDBC驱动程序的文档,以用于验证它是否支持流式LOB而不提供内容长度。
现在是时候从数据库中读取LOB数据了。 同样,您将JdbcTemplate与相同的实例变量lobHandler和对DefaultLobHandler的引用一起使用。 以下示例显示了如何执行此操作:
3.8.3 传入IN子句的值列表
SQL标准允许基于包含变量值列表的表达式选择行。 一个典型的示例是select * from T_ACTOR where id in (1, 2, 3)。 JDBC标准不直接为准备好的语句支持此变量列表。 您不能声明可变数量的占位符。 您需要准备好所需数量的占位符的多种变体,或者一旦知道需要多少个占位符,就需要动态生成SQL字符串。 NamedParameterJdbcTemplate和JdbcTemplate中提供的命名参数支持采用后一种方法。 您可以将值作为原始对象的java.util.List传入。 此列表用于插入所需的占位符,并在语句执行期间传递值。
传递许多值时要小心。 JDBC标准不保证您可以为in表达式列表使用100个以上的值。 各种数据库都超过了这个数目,但是它们通常对允许多少个值有硬性限制。 例如,Oracle的限制为1000。
除了值列表中的原始值之外,您还可以创建对象数组的java.util.List。 该列表可以支持为in子句定义的多个表达式,例如,T_ACTOR的select * from((1,'Johnson'),(2,'Harrop'\))中的(id,last_name)。 当然,这要求您的数据库支持此语法。
3.8.4 处理存储过程调用的复杂类型
调用存储过程时,有时可以使用特定于数据库的复杂类型。 为了容纳这些类型,Spring提供了一个SqlReturnType来处理从存储过程调用返回的值,并提供SqlTypeValue作为参数作为参数传递给存储过程。
SqlReturnType接口具有必须实现的单个方法(名为getTypeValue)。 此接口用作SqlOutParameter声明的一部分。 以下示例显示了返回用户声明类型为ITEM_TYPE的Oracle STRUCT对象的值:
您可以使用SqlTypeValue将Java对象(例如TestItem)的值传递给存储过程。 SqlTypeValue接口具有必须实现的单个方法(名为createTypeValue)。 传入活动连接,您可以使用它来创建特定于数据库的对象,例如StructDescriptor实例或ArrayDescriptor实例。 下面的示例创建一个StructDescriptor实例:
现在,您可以将此SqlTypeValue添加到包含用于存储过程的execute调用的输入参数的Map中。
SqlTypeValue的另一个用途是将值数组传递给Oracle存储过程。 在这种情况下,Oracle有其自己的内部ARRAY类,您可以使用SqlTypeValue创建Oracle ARRAY的实例,并使用Java ARRAY中的值填充它,如以下示例所示:
最后更新于