科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道Spring让LOB数据操作变得简单易行

Spring让LOB数据操作变得简单易行

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

本文讲解了在 Spring 中处理 LOB 数据的原理和方法

作者:陈雄华 来源:Impress Watch中文站 2007年10月13日

关键字:

  • 评论
  • 分享微博
  • 分享邮件

在本页阅读全文(共5页)

在 Spring JDBC 中操作 LOB 数据

  插入 LOB 数据

  假设我们有一个用于保存论坛帖子的 t_post 表,拥有两个 LOB 字段,其中 post_text 是 CLOB 类型,而 post_attach 是 BLOB 类型。下面,我们来编写插入一个帖子记录的代码:
  
  清单 3. 添加 LOB 字段数据

package com.baobaotao.dao.jdbc; 
… 
import java.sql.PreparedStatement; 
import java.sql.SQLException; 
import org.springframework.jdbc.core.support.AbstractLobCreatingPreparedStatementCallback; 
import org.springframework.jdbc.support.lob.LobCreator; 
import org.springframework.jdbc.support.lob.LobHandler; 

public class PostJdbcDao extends JdbcDaoSupport implements PostDao { 
  private LobHandler lobHandler; ① 定义 LobHandler 属性 
  public LobHandler getLobHandler() { 
    return lobHandler; 
  } 
  public void setLobHandler(LobHandler lobHandler) { 
    this.lobHandler = lobHandler; 
  } 
  public void addPost(final Post post) {     
    String sql = " INSERT INTO t_post(post_id,user_id,post_text,post_attach)" 
        + " VALUES(?,?,?,?)"; 
    getJdbcTemplate().execute(sql, 
      new AbstractLobCreatingPreparedStatementCallback(this.lobHandler) { ② 
          protected void setValues(PreparedStatement ps,LobCreator lobCreator) 
                      throws SQLException { 
            ps.setInt(1, 1);   
            ps.setInt(2, post.getUserId());   
            ③ 设置 CLOB 字段 
            lobCreator.setClobAsString(ps, 3, post.getPostText()); 
            ④ 设置 BLOB 字段 
            lobCreator.setBlobAsBytes(ps, 4, post.getPostAttach()); 
          } 
        }); 
  } 
… 
} 


  首先,我们在 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 配置

… 
<bean id="nativeJdbcExtractor"  
class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor" 
lazy-init="true"/> 
<bean id="oracleLobHandler"  
class="org.springframework.jdbc.support.lob.OracleLobHandler"  
lazy-init="true"> 
   <property name="nativeJdbcExtractor" ref="nativeJdbcExtractor"/> ① 设置本地 Jdbc 对象抽取器 
</bean> 
<bean id="postDao" class="com.baobaotao.dao.jdbc.PostJdbcDao"> 
   <property name="lobHandler" ref="oracleLobHandler"/> ② 设置 LOB 处理器 
</bean> 

  大家可能已经注意到 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 的配置

<bean id="defaultLobHandler"  
class="org.springframework.jdbc.support.lob.DefaultLobHandler"  
lazy-init="true"/> 
<bean id="postDao" class="com.baobaotao.dao.jdbc.PostJdbcDao"> 
   <property name="lobHandler" ref=" defaultLobHandler"/>  
<property name="jdbcTemplate" ref="jdbcTemplate" /> 
</bean> 
 

  DefaultLobHandler 只是简单地代理标准 JDBC 的 PreparedStatement 和 ResultSet 对象,由于并不需要访问数据库驱动本地的 JDBC 对象,所以它不需要 NativeJdbcExtractor 的帮助。您可以通过以下的代码测试 PostJdbcDao 的 addPost() 方法:

  清单 6. 测试 PostJdbcDao 的 addPost() 方法

package com.baobaotao.dao.jdbc; 

import org.springframework.core.io.ClassPathResource; 
import org.springframework.test.AbstractDependencyInjectionSpringContextTests; 
import org.springframework.util.FileCopyUtils; 
import com.baobaotao.dao.PostDao; 
import com.baobaotao.domain.Post; 
public class TestPostJdbcDaoextends AbstractDependencyInjectionSpringContextTests { 
  private PostDao postDao; 
  public void setPostDao(PostDao postDao) { 
    this.postDao = postDao; 
  } 
  protected String[] getConfigLocations() { 
    return new String[]{"classpath:applicationContext.xml"}; 
  } 
  public void testAddPost() throws Throwable{ 
    Post post = new Post(); 
    post.setPostId(1); 
    post.setUserId(2); 
    ClassPathResource res = new ClassPathResource("temp.jpg"); ① 获取图片资源 
    byte[] mockImg = FileCopyUtils.copyToByteArray(res.getFile());  ② 读取图片文件的数据 
    post.setPostAttach(mockImg); 
    post.setPostText("测试帖子的内容"); 
    postDao.addPost(post); 
  } 
} 

  这里,有几个知识点需要稍微解释一下:AbstractDependencyInjectionSpringContextTests 是 Spring 专门为测试提供的类,它能够直接从 IoC 容器中装载 Bean。此外,我们使用了 ClassPathResource 加载图片资源,并通过 FileCopyUtils 读取文件的数据。ClassPathResource 和 FileCopyUtils 都是 Spring 提供的非常实用的工具类。
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章