- 浏览: 327832 次
- 性别:
- 来自: 北京
-
文章分类
最新评论
-
lzy.je:
期待FSF的!1985.10成立到现在GNU有多少大牛的项目数 ...
改变IT世界的11大Apache开源技术 -
dotaking:
7、8不了解
改变IT世界的11大Apache开源技术
Spring让LOB数据操作变得简单易行
本文讲解了在 Spring 中处理 LOB 数据的原理和方法,对于 Spring JDBC 以及 Spring 所集成的第三方 ORM 框架(包括 JPA、Hibernate 和 iBatis)如何处理 LOB 数据进行了阐述。
概述
LOB 代表大对象数据,包括 BLOB 和 CLOB 两种类型,前者用于存储大块的二进制数据,如图片数据,视频数据等,而后者用于存储长文本数据,如论坛的帖子内容,产品的详细描述等。值得注意的是:在不同的数据库中,大对象对应的字段类型是不尽相同的,如 DB2 对应 BLOB/CLOB,MySql 对应 BLOB/LONGTEXT,SqlServer 对应 IMAGE/TEXT。需要指出的是,有些数据库的大对象类型可以象简单类型一样访问,如 MySql 的 LONGTEXT 的操作方式和 VARCHAR 类型一样。在一般情况下, LOB 类型数据的访问方式不同于其它简单类型的数据,我们经常会以流的方式操作 LOB 类型的数据。此外,LOB 类型数据的访问不是线程安全的,需要为其单独分配相应的数据库资源,并在操作完成后释放资源。最后,Oracle 9i 非常有个性地采用非 JDBC 标准的 API 操作 LOB 数据。所有这些情况给编写操作 LOB 类型数据的程序带来挑战,Spring 在 org.springframework.jdbc.support.lob 包中为我们提供了相应的帮助类,以便我们轻松应对这头拦路虎。 Spring 大大降低了我们处理 LOB 数据的难度。首先,Spring 提供了 NativeJdbcExtractor 接口,您可以在不同环境里选择相应的实现类从数据源中获取本地 JDBC 对象;其次,Spring 通过 LobCreator 接口取消了不同数据厂商操作 LOB 数据的差别,并提供了创建 LobCreator 的 LobHandler 接口,您只要根据底层数据库类型选择合适的 LobHandler 进行配置即可。 本文将详细地讲述通过 Spring JDBC 插入和访问 LOB 数据的具体过程。不管是以块的方式还是以流的方式,您都可以通过 LobCreator 和 LobHandler 方便地访问 LOB 数据。对于 ORM 框架来说,JPA 拥有自身处理 LOB 数据的配置类型,Spring 为 Hibernate 和 iBatis 分别提供了 LOB 数据类型的配置类,您仅需要使用这些类进行简单的配置就可以像普通类型一样操作 LOB 类型数据。 本地 JDBC 对象 当您在 Web 应用服务器或 Spring 中配置数据源时,从数据源中返回的数据连接对象是本地 JDBC 对象(如 DB2Connection、OracleConnection)的代理类,这是因为数据源需要改变数据连接一些原有的行为以便对其进行控制:如调用 Connection#close() 方法时,将数据连接返回到连接池中而非将其真的关闭。 在访问 LOB 数据时,根据数据库厂商的不同,可能需要使用被代理前的本地 JDBC 对象(如 DB2Connection 或 DB2ResultSet)特有的 API。为了从数据源中获取本地 JDBC 对象, Spring 定义了 org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor 接口并提供了相应的实现类。NativeJdbcExtractor 定义了从数据源中抽取本地 JDBC 对象的若干方法:
有些简单的数据源仅对 Connection 对象进行代理,这时可以直接使用 SimpleNativeJdbcExtractor 实现类。但有些数据源(如 Jakarta Commons DBCP)会对所有的 JDBC 对象进行代理,这时,就需要根据具体的情况选择适合的抽取器实现类了。下表列出了不同数据源本地 JDBC 对象抽取器的实现类:
下面的代码演示了从 DBCP 数据源中获取 DB2 的本地数据库连接 DB2Connection 的方法: 清单 1. 获取本地数据库连接
在 ① 处我们通过 DataSourceUtils 获取当前线程绑定的数据连接,为了使用线程上下文相关的事务,通过 DataSourceUtils 从数据源中获取连接是正确的做法,如果直接通过 dateSource 获取连接,则将得到一个和当前线程上下文无关的数据连接实例。 JdbcTemplate 可以在配置时注入一个本地 JDBC 对象抽取器,要使代码 清单 1 正确运行,我们必须进行如下配置: 清单 2. 为 JdbcTemplate 装配本地 JDBC 对象抽取器
在获取 DB2 的本地 Connection 实例后,我们就可以使用该对象的一些特有功能了,如使用 DB2Connection 的特殊 API 对 LOB 对象进行操作。
LobCreator
虽然 JDBC 定义了两个操作 LOB 类型的接口:java.sql.Blob 和 java.sql.Clob,但有些厂商的 JDBC 驱动程序并不支持这两个接口。为此,Spring 定义了一个独立于 java.sql.Blob/Clob 的 LobCreator 接口,以统一的方式操作各种数据库的 LOB 类型数据。因为 LobCreator 本身持有 LOB 所对应的数据库资源,所以它不是线程安全的,一个 LobCreator 只能操作一个 LOB 数据。 为了方便在 PreparedStatement 中使用 LobCreator,您可以直接使用 JdbcTemplate#execute(String sql,AbstractLobCreatingPreparedStatementCallback lcpsc) 方法。下面对 LobCreator 接口中的方法进行简要说明:
LobHandler LobHandler 接口为操作 BLOB/CLOB 提供了统一访问接口,而不管底层数据库究竟是以大对象的方式还是以一般数据类型的方式进行操作。此外,LobHandler 还充当了 LobCreator 的工厂类。 大部分数据库厂商的 JDBC 驱动程序(如 DB2)都以 JDBC 标准的 API 操作 LOB 数据,但 Oracle 9i 及以前的 JDBC 驱动程序采用了自己的 API 操作 LOB 数据,Oracle 9i 直接使用自己的 API 操作 LOB 数据,且不允许通过 PreparedStatement 的 setAsciiStream()、setBinaryStream()、setCharacterStream() 等方法填充流数据。Spring 提供 LobHandler 接口主要是为了迁就 Oracle 特立独行的作风。所以 Oracle 必须使用 OracleLobHandler 实现类,而其它的数据库统一使用 DefaultLobHandler 就可以了。Oracle 10g 改正了 Oracle 9i 这个异化的风格,终于天下归一了,所以 Oracle 10g 也可以使用 DefaultLobHandler。 下面,我们来看一下 LobHandler 接口的几个重要方法:
在 Spring JDBC 中操作 LOB 数据
插入 LOB 数据 假设我们有一个用于保存论坛帖子的 t_post 表,拥有两个 LOB 字段,其中 post_text 是 CLOB 类型,而 post_attach 是 BLOB 类型。下面,我们来编写插入一个帖子记录的代码: 清单 3. 添加 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() 方法
这里,有几个知识点需要稍微解释一下:AbstractDependencyInjectionSpringContextTests 是 Spring 专门为测试提供的类,它能够直接从 IoC 容器中装载 Bean。此外,我们使用了 ClassPathResource 加载图片资源,并通过 FileCopyUtils 读取文件的数据。ClassPathResource 和 FileCopyUtils 都是 Spring 提供的非常实用的工具类。
以块数据方式读取 LOB 数据
您可以直接用数据块的方式读取 LOB 数据:用 String 读取 CLOB 字段的数据,用 byte[] 读取 BLOB 字段的数据。在 PostJdbcDao 中添加一个 getAttachs() 方法,以便获取某一用户的所有带附件的帖子: 清单 7. 以块数据访问 LOB 数据
通过 JdbcTemplate 的 List query(String sql, Object[] args, RowMapper rowMapper) 接口处理行数据的映射。在 RowMapper 回调的 mapRow() 接口方法中,通过 LobHandler 以 byte[] 获取 BLOB 字段的数据。 以流数据方式读取 LOB 数据 由于 LOB 数据可能很大(如 100M),如果直接以块的方式操作 LOB 数据,需要消耗大量的内存资源,对应用程序整体性能产生巨大的冲击。对于体积很大的 LOB 数据,我们可以使用流的方式进行访问,减少内存的占用。JdbcTemplate 为此提供了一个 Object query(String sql, Object[] args, ResultSetExtractor rse) 方法,ResultSetExtractor 接口拥有一个处理流数据的抽象类 org.springframework.jdbc.core.support.AbstractLobStreamingResultSetExtractor,可以通过扩展此类用流的方式操作 LOB 字段的数据。下面我们为 PostJdbcDao 添加一个以流的方式获取某个帖子附件的方法: 清单 8. 以流方式访问 LOB 数据
通过扩展 AbstractLobStreamingResultSetExtractor 抽象类,在 streamData(ResultSet rs) 方法中以流的方式读取 LOB 字段数据,如 ④ 所示。这里我们又利用到了 Spring 的工具类 FileCopyUtils 将输入流的数据拷贝到输出流中。在 getAttach() 方法中通过入参 OutputStream os 接收 LOB 的数据,如 ① 所示。您可以同时覆盖抽象类中的 handleNoRowFound() 方法,定义未找到数据行时的处理逻辑。 在 JPA 中操作 LOB 数据 在 JPA 中 LOB 类型的持久化更加简单,仅需要通过特殊的 LOB 注释(Annotation)就可以达到目的。我们对 Post 中的 LOB 属性类型进行注释: 清单 9. 注释 LOB 类型属性
postText 属性对应 T_POST 表的 POST_TEXT 字段,该字段的类型是 LONTTEXT,并且非空。JPA 通过 @Lob 将属性标注为 LOB 类型,如 ①-1 和 ②-1 所示。通过 @Basic 指定 LOB 类型数据的获取策略,FetchType.EAGER 表示非延迟加载,而 FetchType.LAZY 表示延迟加载,如 ①-2 和 ②-2 所示。通过 @Column 的 columnDefinition 属性指定数据表对应的 LOB 字段类型,如 ①-3 和 ②-3 所示。
在 Hibernate 中操作 LOB 数据
下面我们使用 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 数据时,需要在事务环境下才能工作,所以必须事先配置事务管理器,否则会抛出异常。 在 iBatis 中操作 LOB 数据 iBatis 为处理不同类型的数据定义了一个统一的接口:com.ibatis.sqlmap.engine.type.TypeHandler。这个接口类似于 Hibernate 的 UserType。iBatis 本身拥有该接口的众多实现类,如 LongTypeHandler、DateTypeHandler 等,但没有为 LOB 类型提供对应的实现类。Spring 在 org.springframework.orm.ibatis.support 包中为我们提供了几个处理 LOB 类型的 TypeHandler 实现类:
当结果集中包括 LOB 数据时,需要在结果集映射配置项中指定对应的 Handler 类,下面我们采用 Spring 所提供的实现类对 Post 结果集的映射进行配置。 清单 12 . 对 LOB 数据进行映射
当 iBatis 引擎从结果集中读取或更改 LOB 类型数据时,都需要指定处理器。我们在 ① 和 ② 处为读取 LOB 类型的数据指定处理器,相似的,在 ③ 和 ④ 处为插入 LOB 类型的数据也指定处理器。 此外,我们还必须为 SqlClientMap 提供一个 LobHandler: 清单 13. 将 LobHandler 注入到 SqlClientMap 中
处理 LOB 数据时,Spring 要求在事务环境下工作,所以还必须配置一个事务管理器。iBatis 的事务管理器和 Spring JDBC 事务管理器相同,此处不再赘述。 小结 本文就 Spring 中如何操作 LOB 数据进行较为全面的讲解,您仅需简单地配置 LobHandler 就可以直接在程序中象一般数据一样操作 LOB 数据了。对于 ORM 框架来说,Spring 为它们分别提供了支持类,您仅要使用相应的支持类进行配置就可以了。因此您会发现在传统 JDBC 程序操作 LOB 头疼的问题将变得轻松了许多。 |
发表评论
-
CGLIB-Spring的一种反射机制
2009-08-04 00:12 977Spring 在进行反射时候主要有两种策略,一种是直接用JDK ... -
Spring声明式事务管理及事务嵌套
2009-08-04 00:43 839Spring声明式事务管理及事务嵌套:Spring动态代理的一 ... -
CGLIB-Spring的一种反射机制
2009-08-04 00:12 1023Spring 在进行反射时候主要有两种策略,一种是直接用JDK ... -
Spring声明式事务管理及事务嵌套
2009-08-04 00:43 1855Spring声明式事务管理及 ... -
怎样使用Spring发邮件?
2009-04-20 14:32 827怎样使用Spring发邮件? 2007-07- ... -
spring框架说明
2009-04-20 14:35 805spring框架 2007-06-27 15:18: ... -
spring执行定时任务
2009-04-20 14:37 770spring执行定时任务 2007-07-19 1 ... -
Spring的依赖关系(JAR)
2009-04-20 14:46 749Spring的依赖关系(JAR) 2007-06- ... -
使用Spring来创建一个简单的工作流引擎
2009-04-20 14:48 906使用Spring来创建一个简 ... -
spring各种邮件发送
2009-06-19 17:00 1093Spring邮件抽象层的主要包为org.springframe ... -
用Spring快速开发jms应用(JBOSS服务器)
2009-06-19 17:01 807异步进程通信是面向服 ... -
使用Spring来创建一个简单的工作流引擎
2009-06-19 17:06 890spring是支持控制反转编 ... -
Spring XML配置十二个最佳实践
2009-06-19 17:12 764在这篇文章里,对于Spri ... -
基于Spring的Hibernate Search全文检索功能示例
2009-06-19 17:14 798数据库:Oracle 9iJDBC驱动:OJDBC14开发环境 ... -
spring 事务管理
2009-07-08 17:33 1176关键字: 事务 spring Spring框架引人注目 ... -
为什么要用spring?
2009-07-08 18:16 840为什么要用spring, 下面 ...
相关推荐
总结起来,本文通过一个简单的Spring案例展示了如何操作LOB字段,包括创建DAO方法,使用`JdbcTemplate`进行数据库操作,以及在Web应用中处理文件上传。同时,我们也了解了如何配置Spring的`JdbcTemplate`和数据库...
如果LOB数据大小超过指定的上限值或者数据行空间不足,则LOB数据行中将只存放指针。 在存储LOB数据的方法上,文档中提到了两种主要策略。一种是建立具有Image字段的SQL Server数据库关系表,并使用sp_tableoption...
在本文中,我们将深入探讨如何在Java环境下,利用Spring和Hibernate框架处理Oracle数据库中的LOB(Large Object)字段。LOB字段通常用于存储大体积的数据,如文本、图片或视频。在实际开发中,处理这类数据时可能会...
通过spring存blob和clob数据到sybase数据库中,压缩包里包含了三种方式,(1)spring+hibernate,切面事务(aop),存lob数据,(2)spring+hibernate存lob数据,(3)spring+jdbc存lob数据。
在Oracle数据库中,LOB数据类型的存储和优化是非常重要的,因为LOB数据类型占用的存储空间较大,且其读写操作也较慢。 在创建包含LOB字段的表时,Oracle将同时创建两个段来容纳指定的列,这两个段分别为LOBINDEX和...
在DB2中,LOB数据类型的创建和维护比传统的RDBMS对象要复杂得多。创建LOB数据对象时,DBA需要特别注意记录大小必须小于等于DB2表中定义的页面大小。页面大小包括了控制信息,比如页面头(20字节)、行头(6字节)...
总之,`DBMS_LOB`是Oracle数据库管理LOB数据的关键工具,对于处理大量非结构化数据的开发者来说,理解和熟练使用这个包是必不可少的技能。通过深入学习和实践,可以有效地利用Oracle的LOB功能满足大数据存储和处理的...
Oracle数据库中处理LOB大对象的知识点包含了多种类型的数据存储方式和操作方法,以下是根据提供的文件内容总结出的详细知识点: 1. LOB大对象处理的概念和作用: - LOB是Large Object的缩写,也称为大对象,用于在...
7. **避免不必要的数据复制**:当需要对 LOB 数据进行操作时,尽量避免不必要的数据复制过程,例如通过使用 `KEEP` 或 `BASICFILE` 子类型来减少数据移动。 8. **使用 Direct Path 插入**:在插入大量 LOB 数据时,...
插入LOB数据通常涉及多次数据库操作,因为数据被分块读写。例如: ```sql INSERT INTO mylobs VALUES (1, EMPTY_BLOB(), EMPTY_CLOB()); DECLARE lob_loc BLOB; BEGIN SELECT blob_data INTO lob_loc FROM ...
在数据库操作中,LOB字段的处理往往比常规的行数据更为复杂,因为它涉及到大块的数据读取、写入和管理。"Oracle LOB字段处理工具"就是为了简化这些操作而设计的软件。 这款工具主要针对Oracle数据库中的BLOB...
可以在插入行时设置persistent LOB 到 NULL,例如在没有 LOB 数据时。如果想使用 OCI 或 DBMS_LOB 函数,需要将 LOB 列设置为非 NULL 或 empty。 二、LOB 的存储 LOB 可以存储在表中,也可以作为对象类型的属性。 ...
以上代码首先通过查询获取了目标行的`document`字段的LOB定位器,然后准备了要写入的文本数据,并通过`DBMS_LOB.WRITE()`过程将文本写入CLOB字段。 #### 结论 本文详细介绍了在Oracle数据库中如何使用和维护LOB...
Lob库为前端开发者提供了一层友好的封装,使得调用LOB API变得更加简单。它通过JavaScript对象和方法,将复杂的HTTP请求和JSON格式化隐藏在底层,让开发者能够专注于业务逻辑,而不是处理低级别的网络通信。例如,你...
JYTHON允许用户利用Python的灵活性和强大功能进行复杂的数据处理,例如处理LOB数据的格式化、压缩或者解压缩等操作。这个KM对于那些需要对LOB数据进行特定处理或清洗的场景非常有用。 在实际应用中,这两个KM可以...
为了有效地管理和操作LOB数据,Oracle提供了专门的机制来进行数据的录入。 1. **声明LOB类型列** 创建包含LOB类型列的表时,需要指定相应的存储选项。例如,可以创建一个名为 `tLob` 的表,其中包含 `CLOB` 和 `...
测试oracle数据库中,lob字段在不同参数条件下,删除数据后占用空间的情况。 测试1 测试disable storage in row下的lob字段 测试2 测试非disable storage in row模式下 该模式为默认模式,既小于4k的数据不会存在lob...
Oracle的LOB解决方案进一步完善了其数据库管理系统,使得存储和访问大非结构化数据变得更加便捷和统一。 总的来说,这篇文章深入浅出地讲解了Oracle数据库如何使用LOB类型存储非结构化数据,以及如何通过JDBC接口...
`OCI_LOB`样例程序是针对LOB数据类型在OCI中的操作提供的一系列示例代码,旨在帮助开发者理解如何在Oracle数据库中创建、读取、更新和删除LOB对象。下面将详细介绍这些知识点。 1. OCI LOB基础概念: - BLOB:二...
在Oracle数据库中,当需要存储超过VARCHAR2类型最大限制(4000个字符或2000个汉字)的数据时,可以使用LOB(Large Object)类型,包括BLOB(Binary Large OBject)、CLOB(Character Large OBject)以及BFILE。...