Spring 让 LOB 数据操作变得简单易行
本文讲解了在 Spring 中处理 LOB 数据的原理和方法,对于 Spring JDBC 以及 Spring 所集成的第三方 ORM 框架(包括 JPA、Hibernate 和 iBatis)如何处理 LOB 数据进行了阐述。
<!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
回页首
?
在获取 DB2 的本地 Connection 实例后,我们就可以使用该对象的一些特有功能了,如使用 DB2Connection 的特殊 API 对 LOB 对象进行操作。
回页首
?
首先,我们在 PostJdbcDao
中引入了一个 LobHandler
属性,如 ① 所示,并通过 JdbcTemplate#execute(String sql,AbstractLobCreatingPreparedStatementCallback lcpsc)
方法完成插入 LOB 数据的操作。我们通过匿名内部类的方式定义 LobCreatingPreparedStatementCallback
抽象类的子类,其构造函数需要一个 LobHandler
入参,如 ② 所示。在匿名类中实现了父类的抽象方法 setValues(PreparedStatement ps,LobCreator lobCreator)
,在该方法中通过 lobCreator
操作 LOB 对象,如 ③、④ 所示,我们分别通过字符串和二进制数组填充 BLOB 和 CLOB 的数据。您同样可以使用流的方式填充 LOB 数据,仅需要调用 lobCreator 相应的流填充方法即可。
我们需要调整 Spring 的配置文件以配合我们刚刚定义的 PostJdbcDao。假设底层数据库是 Oracle,可以采用以下的配置方式:
清单 4. Oracle 数据库的 LobHandler 配置
?
大家可能已经注意到 nativeJdbcExtractor
和 oracleLobHandler
Bean 都设置为 lazy-init="true"
,这是因为 nativeJdbcExtractor
需要通过运行期的反射机制获取底层的 JDBC 对象,所以需要避免在 Spring 容器启动时就实例化这两个 Bean。
LobHandler 需要访问本地 JDBC 对象,这一任务委托给 NativeJdbcExtractor
Bean 来完成,因此我们在 ① 处为 LobHandler 注入了一个 nativeJdbcExtractor
。最后,我们把 lobHandler
Bean 注入到需要进行 LOB 数据访问操作的 PostJdbcDao 中,如 ② 所示。
如果底层数据库是 DB2、SQL Server、MySQL 等非 Oracle 的其它数据库,则只要简单配置一个 DefaultLobHandler
就可以了,如下所示:
清单 5. 一般数据库 LobHandler 的配置
?
DefaultLobHandler 只是简单地代理标准 JDBC 的 PreparedStatement 和 ResultSet 对象,由于并不需要访问数据库驱动本地的 JDBC 对象,所以它不需要 NativeJdbcExtractor 的帮助。您可以通过以下的代码测试 PostJdbcDao 的 addPost()
方法:
清单 6. 测试 PostJdbcDao 的 addPost() 方法


回页首
回页首
提示
使用 Spring JDBC 时,我们除了可以按 byte[]、String 类型处理 LOB 数据外,还可以使用流的方式操作 LOB 数据,当 LOB 数据体积较大时,流操作是唯一可行的方式。可惜,Spring 并未提供以流方式操作 LOB 数据的 UserType(记得 Spring 开发组成员认为在实现上存在难度)。不过,www.atlassian.com 替 Spring 完成了这件难事,读者可以通过 这里 了解到这个满足要求的 BlobInputStream
类型。
Hibernate 为处理特殊数据类型字段定义了一个接口:org.hibernate.usertype.UserType
。Spring 在 org.springframework.orm.hibernate3.support
包中为 BLOB 和 CLOB 类型提供了几个 UserType
的实现类。因此,我们可以在 Hibernate 的映射文件中直接使用这两个实现类轻松处理 LOB 类型的数据。
BlobByteArrayType
:将 BLOB 数据映射为 byte[]
类型的属性; BlobStringType
:将 BLOB 数据映射为 String
类型的属性; BlobSerializableType
:将 BLOB 数据映射为 Serializable
类型的属性; ClobStringType
:将 CLOB 数据映射为 String
类型的属性; 下面我们使用 Spring 的 UserType
为 Post 配置 Hibernate 的映射文件,如 清单 10 所示:
清单 10 . LOB 数据映射配置
?
postText
为 String
类型的属性,对应数据库的 CLOB 类型,而 postAttach
为 byte[]
类型的属性,对应数据库的 BLOB 类型。分别使用 Spring 所提供的相应 UserType
实现类进行配置,如 ① 和 ② 处所示。
在配置好映射文件后,还需要在 Spring 配置文件中定义 LOB 数据处理器,让 SessionFactory 拥有处理 LOB 数据的能力:
清单 11 . 将 LobHandler 注入到 SessionFactory 中
?
在一般的数据库(如 DB2)中,仅需要简单地使用 HibernateTemplate#save(Object entity)
等方法就可以正确的保存 LOB 数据了。如果是 Oracle 9i 数据库,还需要配置一个本地 JDBC 抽取器,并使用特定的 LobHandler 实现类,如 清单 4 所示。
使用 LobHandler 操作 LOB 数据时,需要在事务环境下才能工作,所以必须事先配置事务管理器,否则会抛出异常。
?



回页首
?

为每一个 LOB 类型字段分别指定处理器并不是一个好主意,iBatis 允许在 sql-map-config.xml 配置文件中通过 <typeHandler> 标签统一定义特殊类型数据的处理器,如:
<typeHandler jdbcType="CLOB" javaType="java.lang.String" callback="org.springframework.orm.ibatis.support.ClobStringTypeHandler"/>
当 iBatis 引擎从结果集中读取或更改 LOB 类型数据时,都需要指定处理器。我们在 ① 和 ② 处为读取 LOB 类型的数据指定处理器,相似的,在 ③ 和 ④ 处为插入 LOB 类型的数据也指定处理器。
此外,我们还必须为 SqlClientMap 提供一个 LobHandler:
清单 13. 将 LobHandler 注入到 SqlClientMap 中
?
处理 LOB 数据时,Spring 要求在事务环境下工作,所以还必须配置一个事务管理器。iBatis 的事务管理器和 Spring JDBC 事务管理器相同,此处不再赘述。
?



回页首
小结
本文就 Spring 中如何操作 LOB 数据进行较为全面的讲解,您仅需简单地配置 LobHandler 就可以直接在程序中象一般数据一样操作 LOB 数据了。对于 ORM 框架来说,Spring 为它们分别提供了支持类,您仅要使用相应的支持类进行配置就可以了。因此您会发现在传统 JDBC 程序操作 LOB 头疼的问题将变得轻松了许多。