欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
Spring 讓 LOB 數據操作變得簡(jiǎn)單易行
本文講解了在 Spring 中處理 LOB 數據的原理和方法,對于 Spring JDBC 以及 Spring 所集成的第三方 ORM 框架(包括 JPA、Hibernate 和 iBatis)如何處理 LOB 數據進(jìn)行了闡述。

概述

LOB 代表大對象數據,包括 BLOB 和 CLOB 兩種類(lèi)型,前者用于存儲大塊的二進(jìn)制數據,如圖片數據,視頻數據等,而后者用于存儲長(cháng)文本數據,如論壇的帖子內容,產(chǎn)品的詳細描述等。值得注意的是:在不同的數據庫中,大對象對應的字段類(lèi)型是不盡相同的,如 DB2 對應 BLOB/CLOB,MySql 對應 BLOB/LONGTEXT,SqlServer 對應 IMAGE/TEXT。需要指出的是,有些數據庫的大對象類(lèi)型可以象簡(jiǎn)單類(lèi)型一樣訪(fǎng)問(wèn),如 MySql 的 LONGTEXT 的操作方式和 VARCHAR 類(lèi)型一樣。在一般情況下, LOB 類(lèi)型數據的訪(fǎng)問(wèn)方式不同于其它簡(jiǎn)單類(lèi)型的數據,我們經(jīng)常會(huì )以流的方式操作 LOB 類(lèi)型的數據。此外,LOB 類(lèi)型數據的訪(fǎng)問(wèn)不是線(xiàn)程安全的,需要為其單獨分配相應的數據庫資源,并在操作完成后釋放資源。最后,Oracle 9i 非常有個(gè)性地采用非 JDBC 標準的 API 操作 LOB 數據。所有這些情況給編寫(xiě)操作 LOB 類(lèi)型數據的程序帶來(lái)挑戰,Spring 在 org.springframework.jdbc.support.lob 包中為我們提供了相應的幫助類(lèi),以便我們輕松應對這頭攔路虎。

Spring 大大降低了我們處理 LOB 數據的難度。首先,Spring 提供了 NativeJdbcExtractor 接口,您可以在不同環(huán)境里選擇相應的實(shí)現類(lèi)從數據源中獲取本地 JDBC 對象;其次,Spring 通過(guò) LobCreator 接口取消了不同數據廠(chǎng)商操作 LOB 數據的差別,并提供了創(chuàng )建 LobCreator 的 LobHandler 接口,您只要根據底層數據庫類(lèi)型選擇合適的 LobHandler 進(jìn)行配置即可。

本文將詳細地講述通過(guò) Spring JDBC 插入和訪(fǎng)問(wèn) LOB 數據的具體過(guò)程。不管是以塊的方式還是以流的方式,您都可以通過(guò) LobCreator 和 LobHandler 方便地訪(fǎng)問(wèn) LOB 數據。對于 ORM 框架來(lái)說(shuō),JPA 擁有自身處理 LOB 數據的配置類(lèi)型,Spring 為 Hibernate 和 iBatis 分別提供了 LOB 數據類(lèi)型的配置類(lèi),您僅需要使用這些類(lèi)進(jìn)行簡(jiǎn)單的配置就可以像普通類(lèi)型一樣操作 LOB 類(lèi)型數據。





回頁(yè)首


本地 JDBC 對象

當您在 Web 應用服務(wù)器或 Spring 中配置數據源時(shí),從數據源中返回的數據連接對象是本地 JDBC 對象(如 DB2Connection、OracleConnection)的代理類(lèi),這是因為數據源需要改變數據連接一些原有的行為以便對其進(jìn)行控制:如調用 Connection#close() 方法時(shí),將數據連接返回到連接池中而非將其真的關(guān)閉。

在訪(fǎng)問(wèn) LOB 數據時(shí),根據數據庫廠(chǎng)商的不同,可能需要使用被代理前的本地 JDBC 對象(如 DB2Connection 或 DB2ResultSet)特有的 API。為了從數據源中獲取本地 JDBC 對象, Spring 定義了 org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor 接口并提供了相應的實(shí)現類(lèi)。NativeJdbcExtractor 定義了從數據源中抽取本地 JDBC 對象的若干方法:

方法 說(shuō)明
Connection getNativeConnection(Connection con) 獲取本地 Connection 對象
Connection getNativeConnectionFromStatement(Statement stmt) 獲取本地 Statement 對象
PreparedStatement getNativePreparedStatement(PreparedStatement ps) 獲取本地 PreparedStatement 對象
ResultSet getNativeResultSet(ResultSet rs) 獲取本地 ResultSet 對象
CallableStatement getNativeCallableStatement(CallableStatement cs) 獲取本地 CallableStatement 對象

有些簡(jiǎn)單的數據源僅對 Connection 對象進(jìn)行代理,這時(shí)可以直接使用 SimpleNativeJdbcExtractor 實(shí)現類(lèi)。但有些數據源(如 Jakarta Commons DBCP)會(huì )對所有的 JDBC 對象進(jìn)行代理,這時(shí),就需要根據具體的情況選擇適合的抽取器實(shí)現類(lèi)了。下表列出了不同數據源本地 JDBC 對象抽取器的實(shí)現類(lèi):

數據源類(lèi)型 說(shuō)明
WebSphere 4 及以上版本的數據源 org.springframework.jdbc.support.nativejdbc.WebSphereNativeJdbcExtractor
WebLogic 6.1+ 及以上版本的數據源 org.springframework.jdbc.support.nativejdbc.WebLogicNativeJdbcExtractor
JBoss 3.2.4 及以上版本的數據源 org.springframework.jdbc.support.nativejdbc.JBossNativeJdbcExtractor
C3P0 數據源 org.springframework.jdbc.support.nativejdbc.C3P0NativeJdbcExtractor
DBCP 數據源 org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor
ObjectWeb 的 XAPool 數據源 org.springframework.jdbc.support.nativejdbc.XAPoolNativeJdbcExtractor

下面的代碼演示了從 DBCP 數據源中獲取 DB2 的本地數據庫連接 DB2Connection 的方法:


清單 1. 獲取本地數據庫連接
package com.baobaotao.dao.jdbc;                        import java.sql.Connection;                        import COM.ibm.db2.jdbc.net.DB2Connection;                        import org.springframework.jdbc.core.support.JdbcDaoSupport;                        import org.springframework.jdbc.datasource.DataSourceUtils;                        public class PostJdbcDao extends JdbcDaoSupport implements PostDao {                        public void getNativeConn(){                        try {                        Connection conn = DataSourceUtils.getConnection(getJdbcTemplate()                        .getDataSource()); ① 使用 DataSourceUtils 從模板類(lèi)中獲取連接                        ② 使用模板類(lèi)的本地 JDBC 抽取器獲取本地的 Connection                        conn = getJdbcTemplate().getNativeJdbcExtractor().getNativeConnection(conn);                        DB2Connection db2conn = (DB2Connection) conn; ③ 這時(shí)可以強制進(jìn)行類(lèi)型轉換了                        …                        } catch (Exception e) {                        e.printStackTrace();                        }                        }                        }                        

在 ① 處我們通過(guò) DataSourceUtils 獲取當前線(xiàn)程綁定的數據連接,為了使用線(xiàn)程上下文相關(guān)的事務(wù),通過(guò) DataSourceUtils 從數據源中獲取連接是正確的做法,如果直接通過(guò) dateSource 獲取連接,則將得到一個(gè)和當前線(xiàn)程上下文無(wú)關(guān)的數據連接實(shí)例。

JdbcTemplate 可以在配置時(shí)注入一個(gè)本地 JDBC 對象抽取器,要使代碼 清單 1 正確運行,我們必須進(jìn)行如下配置:


清單 2. 為 JdbcTemplate 裝配本地 JDBC 對象抽取器
…                        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"                        destroy-method="close">                        <property name="driverClassName"                        value="${jdbc.driverClassName}" />                        <property name="url" value="${jdbc.url}" />                        <property name="username" value="${jdbc.username}" />                        <property name="password" value="${jdbc.password}" />                        </bean>                        ① 定義 DBCP 數據源的 JDBC 本地對象抽取器                        <bean id="nativeJdbcExtractor"                        class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor"                        lazy-init="true" />                        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">                        <property name="dataSource" ref="dataSource" />                        ② 設置抽取器                        <property name="nativeJdbcExtractor" ref="nativeJdbcExtractor"/>                        </bean>                        <bean id="postDao" class="com.baobaotao.dao.jdbc.PostJdbcDao">                        <property name="jdbcTemplate" ref="jdbcTemplate" />                        </bean>                        

在獲取 DB2 的本地 Connection 實(shí)例后,我們就可以使用該對象的一些特有功能了,如使用 DB2Connection 的特殊 API 對 LOB 對象進(jìn)行操作。

LobCreator

雖然 JDBC 定義了兩個(gè)操作 LOB 類(lèi)型的接口:java.sql.Blobjava.sql.Clob,但有些廠(chǎng)商的 JDBC 驅動(dòng)程序并不支持這兩個(gè)接口。為此,Spring 定義了一個(gè)獨立于 java.sql.Blob/ClobLobCreator 接口,以統一的方式操作各種數據庫的 LOB 類(lèi)型數據。因為 LobCreator 本身持有 LOB 所對應的數據庫資源,所以它不是線(xiàn)程安全的,一個(gè) LobCreator 只能操作一個(gè) LOB 數據。

為了方便在 PreparedStatement 中使用 LobCreator,您可以直接使用 JdbcTemplate#execute(String sql,AbstractLobCreatingPreparedStatementCallback lcpsc) 方法。下面對 LobCreator 接口中的方法進(jìn)行簡(jiǎn)要說(shuō)明:

方法 說(shuō)明
void close() 關(guān)閉會(huì )話(huà),并釋放 LOB 資源
void setBlobAsBinaryStream(PreparedStatement ps, int paramIndex, InputStream contentStream, int contentLength) 通過(guò)流填充 BLOB 數據
void setBlobAsBytes(PreparedStatement ps, int paramIndex, byte[] content) 通過(guò)二進(jìn)制數據填充 BLOB 數據
void setClobAsAsciiStream(PreparedStatement ps, int paramIndex, InputStream asciiStream, int contentLength) 通過(guò) Ascii 字符流填充 CLOB 數據
void setClobAsCharacterStream(PreparedStatement ps, int paramIndex, Reader characterStream, int contentLength) 通過(guò) Unicode 字符流填充 CLOB 數據
void setClobAsString(PreparedStatement ps, int paramIndex, String content) 通過(guò)字符串填充 CLOB 數據

LobHandler

LobHandler 接口為操作 BLOB/CLOB 提供了統一訪(fǎng)問(wèn)接口,而不管底層數據庫究竟是以大對象的方式還是以一般數據類(lèi)型的方式進(jìn)行操作。此外,LobHandler 還充當了 LobCreator 的工廠(chǎng)類(lèi)。

大部分數據庫廠(chǎng)商的 JDBC 驅動(dòng)程序(如 DB2)都以 JDBC 標準的 API 操作 LOB 數據,但 Oracle 9i 及以前的 JDBC 驅動(dòng)程序采用了自己的 API 操作 LOB 數據,Oracle 9i 直接使用自己的 API 操作 LOB 數據,且不允許通過(guò) PreparedStatement 的 setAsciiStream()、setBinaryStream()、setCharacterStream() 等方法填充流數據。Spring 提供 LobHandler 接口主要是為了遷就 Oracle 特立獨行的作風(fēng)。所以 Oracle 必須使用 OracleLobHandler 實(shí)現類(lèi),而其它的數據庫統一使用 DefaultLobHandler 就可以了。Oracle 10g 改正了 Oracle 9i 這個(gè)異化的風(fēng)格,終于天下歸一了,所以 Oracle 10g 也可以使用 DefaultLobHandler。 下面,我們來(lái)看一下 LobHandler 接口的幾個(gè)重要方法:

方法 說(shuō)明
InputStream getBlobAsBinaryStream(ResultSet rs, int columnIndex) 從結果集中返回 InputStream,通過(guò) InputStream 讀取 BLOB 數據
byte[] getBlobAsBytes(ResultSet rs, int columnIndex) 以二進(jìn)制數據的方式獲取結果集中的 BLOB 數據;
InputStream getClobAsAsciiStream(ResultSet rs, int columnIndex) 從結果集中返回 InputStream,通過(guò) InputStreamn 以 Ascii 字符流方式讀取 BLOB 數據
Reader getClobAsCharacterStream(ResultSet rs, int columnIndex) 從結果集中獲取 Unicode 字符流 Reader,并通過(guò) Reader以Unicode 字符流方式讀取 CLOB 數據
String getClobAsString(ResultSet rs, int columnIndex) 從結果集中以字符串的方式獲取 CLOB 數據
LobCreator getLobCreator() 生成一個(gè)會(huì )話(huà)相關(guān)的 LobCreator 對象




回頁(yè)首


在 Spring JDBC 中操作 LOB 數據

插入 LOB 數據

假設我們有一個(gè)用于保存論壇帖子的 t_post 表,擁有兩個(gè) LOB 字段,其中 post_text 是 CLOB 類(lèi)型,而 post_attach 是 BLOB 類(lèi)型。下面,我們來(lái)編寫(xiě)插入一個(gè)帖子記錄的代碼:


清單 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 中引入了一個(gè) LobHandler 屬性,如 ① 所示,并通過(guò) JdbcTemplate#execute(String sql,AbstractLobCreatingPreparedStatementCallback lcpsc) 方法完成插入 LOB 數據的操作。我們通過(guò)匿名內部類(lèi)的方式定義 LobCreatingPreparedStatementCallback 抽象類(lèi)的子類(lèi),其構造函數需要一個(gè) LobHandler 入參,如 ② 所示。在匿名類(lèi)中實(shí)現了父類(lèi)的抽象方法 setValues(PreparedStatement ps,LobCreator lobCreator),在該方法中通過(guò) lobCreator 操作 LOB 對象,如 ③、④ 所示,我們分別通過(guò)字符串和二進(jìn)制數組填充 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>                        

大家可能已經(jīng)注意到 nativeJdbcExtractororacleLobHandler Bean 都設置為 lazy-init="true",這是因為 nativeJdbcExtractor 需要通過(guò)運行期的反射機制獲取底層的 JDBC 對象,所以需要避免在 Spring 容器啟動(dòng)時(shí)就實(shí)例化這兩個(gè) Bean。

LobHandler 需要訪(fǎng)問(wèn)本地 JDBC 對象,這一任務(wù)委托給 NativeJdbcExtractor Bean 來(lái)完成,因此我們在 ① 處為 LobHandler 注入了一個(gè) nativeJdbcExtractor。最后,我們把 lobHandler Bean 注入到需要進(jìn)行 LOB 數據訪(fǎng)問(wèn)操作的 PostJdbcDao 中,如 ② 所示。

如果底層數據庫是 DB2、SQL Server、MySQL 等非 Oracle 的其它數據庫,則只要簡(jiǎn)單配置一個(gè) 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 只是簡(jiǎn)單地代理標準 JDBC 的 PreparedStatement 和 ResultSet 對象,由于并不需要訪(fǎng)問(wèn)數據庫驅動(dòng)本地的 JDBC 對象,所以它不需要 NativeJdbcExtractor 的幫助。您可以通過(guò)以下的代碼測試 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);                        }                        }                        

這里,有幾個(gè)知識點(diǎn)需要稍微解釋一下:AbstractDependencyInjectionSpringContextTests 是 Spring 專(zhuān)門(mén)為測試提供的類(lèi),它能夠直接從 IoC 容器中裝載 Bean。此外,我們使用了 ClassPathResource 加載圖片資源,并通過(guò) FileCopyUtils 讀取文件的數據。ClassPathResourceFileCopyUtils 都是 Spring 提供的非常實(shí)用的工具類(lèi)。

以塊數據方式讀取 LOB 數據

您可以直接用數據塊的方式讀取 LOB 數據:用 String 讀取 CLOB 字段的數據,用 byte[] 讀取 BLOB 字段的數據。在 PostJdbcDao 中添加一個(gè) getAttachs() 方法,以便獲取某一用戶(hù)的所有帶附件的帖子:


清單 7. 以塊數據訪(fǎng)問(wèn) LOB 數據
public List getAttachs(final int userId){                        String sql = "SELECT post_id,post_attach FROM t_post “+                        “where user_id =? and post_attach is not null ";                        return getJdbcTemplate().query(                        sql,new Object[] {userId},                        new RowMapper() {                        public Object mapRow(ResultSet rs, int rowNum) throws SQLException {                        int postId = rs.getInt(1);                        ① 以二進(jìn)制數組方式獲取 BLOB 數據。                        byte[] attach = lobHandler.getBlobAsBytes(rs, 2);                        Post post = new Post();                        post.setPostId(postId);                        post.setPostAttach(attach);                        return post;                        }                        });                        }                        

通過(guò) JdbcTemplate 的 List query(String sql, Object[] args, RowMapper rowMapper) 接口處理行數據的映射。在 RowMapper 回調的 mapRow() 接口方法中,通過(guò) LobHandler 以 byte[] 獲取 BLOB 字段的數據。

以流數據方式讀取 LOB 數據

由于 LOB 數據可能很大(如 100M),如果直接以塊的方式操作 LOB 數據,需要消耗大量的內存資源,對應用程序整體性能產(chǎn)生巨大的沖擊。對于體積很大的 LOB 數據,我們可以使用流的方式進(jìn)行訪(fǎng)問(wèn),減少內存的占用。JdbcTemplate 為此提供了一個(gè) Object query(String sql, Object[] args, ResultSetExtractor rse) 方法,ResultSetExtractor 接口擁有一個(gè)處理流數據的抽象類(lèi) org.springframework.jdbc.core.support.AbstractLobStreamingResultSetExtractor,可以通過(guò)擴展此類(lèi)用流的方式操作 LOB 字段的數據。下面我們?yōu)?PostJdbcDao 添加一個(gè)以流的方式獲取某個(gè)帖子附件的方法:


清單 8. 以流方式訪(fǎng)問(wèn) LOB 數據
…                        public void getAttach(final int postId,final OutputStream os){ ① 用于接收 LOB 數據的輸出流                        String sql = "SELECT post_attach FROM t_post WHERE post_id=? ";                        getJdbcTemplate().query(                        sql, new Object[] {postId},                        new AbstractLobStreamingResultSetExtractor() { ② 匿名內部類(lèi)                        ③ 處理未找到數據行的情況                        protected void handleNoRowFound() throws LobRetrievalFailureException {                        System.out.println("Not Found result!");                        }                        ④ 以流的方式處理 LOB 字段                        public void streamData(ResultSet rs) throws SQLException, IOException {                        InputStream is = lobHandler.getBlobAsBinaryStream(rs, 1);                        if (is != null) {                        FileCopyUtils.copy(is, os);                        }                        }                        }                        );                        }                        

通過(guò)擴展 AbstractLobStreamingResultSetExtractor 抽象類(lèi),在 streamData(ResultSet rs) 方法中以流的方式讀取 LOB 字段數據,如 ④ 所示。這里我們又利用到了 Spring 的工具類(lèi) FileCopyUtils 將輸入流的數據拷貝到輸出流中。在 getAttach() 方法中通過(guò)入參 OutputStream os 接收 LOB 的數據,如 ① 所示。您可以同時(shí)覆蓋抽象類(lèi)中的 handleNoRowFound() 方法,定義未找到數據行時(shí)的處理邏輯。





回頁(yè)首


在 JPA 中操作 LOB 數據

在 JPA 中 LOB 類(lèi)型的持久化更加簡(jiǎn)單,僅需要通過(guò)特殊的 LOB 注釋?zhuān)ˋnnotation)就可以達到目的。我們對 Post 中的 LOB 屬性類(lèi)型進(jìn)行注釋?zhuān)?/p>
清單 9. 注釋 LOB 類(lèi)型屬性

package com.baobaotao.domain;                        …                        import javax.persistence.Basic;                        import javax.persistence.Lob;                        import javax.persistence. Column;                        @Entity(name = "T_POST")                        public class Post implements Serializable {                        …                        @Lob ①-1 表示該屬性是 LOB 類(lèi)型的字段                        @Basic(fetch = FetchType.EAGER) ①-2 不采用延遲加載機制                        @Column(name = "POST_TEXT", columnDefinition = "LONGTEXT NOT NULL") ①-3 對應字段類(lèi)型                        private String postText;                        @Lob ②-1 表示該屬性是 LOB 類(lèi)型的字段                        @Basic(fetch = FetchType. LAZY) ②-2 采用延遲加載機制                        @Column(name = "POST_ATTACH", columnDefinition = "BLOB") ②-3 對應字段類(lèi)型                        private byte[] postAttach;                        …                        }                        

postText 屬性對應 T_POST 表的 POST_TEXT 字段,該字段的類(lèi)型是 LONTTEXT,并且非空。JPA 通過(guò) @Lob 將屬性標注為 LOB 類(lèi)型,如 ①-1 和 ②-1 所示。通過(guò) @Basic 指定 LOB 類(lèi)型數據的獲取策略,FetchType.EAGER 表示非延遲加載,而 FetchType.LAZY 表示延遲加載,如 ①-2 和 ②-2 所示。通過(guò) @ColumncolumnDefinition 屬性指定數據表對應的 LOB 字段類(lèi)型,如 ①-3 和 ②-3 所示。

關(guān)于 JPA 注釋的更多信息,請閱讀 參考資源 中的相關(guān)技術(shù)文章。





回頁(yè)首


在 Hibernate 中操作 LOB 數據

提示

使用 Spring JDBC 時(shí),我們除了可以按 byte[]、String 類(lèi)型處理 LOB 數據外,還可以使用流的方式操作 LOB 數據,當 LOB 數據體積較大時(shí),流操作是唯一可行的方式??上?,Spring 并未提供以流方式操作 LOB 數據的 UserType(記得 Spring 開(kāi)發(fā)組成員認為在實(shí)現上存在難度)。不過(guò),www.atlassian.com 替 Spring 完成了這件難事,讀者可以通過(guò) 這里 了解到這個(gè)滿(mǎn)足要求的 BlobInputStream 類(lèi)型。

Hibernate 為處理特殊數據類(lèi)型字段定義了一個(gè)接口:org.hibernate.usertype.UserType。Spring 在 org.springframework.orm.hibernate3.support 包中為 BLOB 和 CLOB 類(lèi)型提供了幾個(gè) UserType 的實(shí)現類(lèi)。因此,我們可以在 Hibernate 的映射文件中直接使用這兩個(gè)實(shí)現類(lèi)輕松處理 LOB 類(lèi)型的數據。

  • BlobByteArrayType:將 BLOB 數據映射為 byte[] 類(lèi)型的屬性;
  • BlobStringType:將 BLOB 數據映射為 String 類(lèi)型的屬性;
  • BlobSerializableType:將 BLOB 數據映射為 Serializable 類(lèi)型的屬性;
  • ClobStringType:將 CLOB 數據映射為 String 類(lèi)型的屬性;

下面我們使用 Spring 的 UserType 為 Post 配置 Hibernate 的映射文件,如 清單 10 所示:


清單 10 . LOB 數據映射配置
<?xml version="1.0" encoding="UTF-8"?>                        <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"                        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">                        <hibernate-mapping auto-import="true" default-lazy="false">                        <class name="com.baobaotao.domain.Post" table="t_post">                        <id name="postId" column="post_id">                        <generator class="identity" />                        </id>                        <property name="userId" column="user_id"/>                        <property name="postText" column="post_text"                        type="org.springframework.orm.hibernate3.support.ClobStringType"/>①對應 CLOB 字段                        <property name="postAttach" column="post_attach"                        type="org.springframework.orm.hibernate3.support.BlobByteArrayType"/>② BLOB 字段                        <property name="postTime" column="post_time" type="date" />                        <many-to-one name="topic" column="topic_id" class="com.baobaotao.domain.Topic" />                        </class>                        </hibernate-mapping>                        

postTextString 類(lèi)型的屬性,對應數據庫的 CLOB 類(lèi)型,而 postAttachbyte[] 類(lèi)型的屬性,對應數據庫的 BLOB 類(lèi)型。分別使用 Spring 所提供的相應 UserType 實(shí)現類(lèi)進(jìn)行配置,如 ① 和 ② 處所示。

在配置好映射文件后,還需要在 Spring 配置文件中定義 LOB 數據處理器,讓 SessionFactory 擁有處理 LOB 數據的能力:


清單 11 . 將 LobHandler 注入到 SessionFactory 中
…                        <bean id="lobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler"                        lazy-init="true" />                        <bean id="sessionFactory"                        class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">                        <property name="dataSource" ref="dataSource" />                        <property name="lobHandler" ref="lobHandler" /> ① 設置 LOB 處理器                        …                        </bean>                        

在一般的數據庫(如 DB2)中,僅需要簡(jiǎn)單地使用 HibernateTemplate#save(Object entity) 等方法就可以正確的保存 LOB 數據了。如果是 Oracle 9i 數據庫,還需要配置一個(gè)本地 JDBC 抽取器,并使用特定的 LobHandler 實(shí)現類(lèi),如 清單 4 所示。

使用 LobHandler 操作 LOB 數據時(shí),需要在事務(wù)環(huán)境下才能工作,所以必須事先配置事務(wù)管理器,否則會(huì )拋出異常。





回頁(yè)首


在 iBatis 中操作 LOB 數據

iBatis 為處理不同類(lèi)型的數據定義了一個(gè)統一的接口:com.ibatis.sqlmap.engine.type.TypeHandler。這個(gè)接口類(lèi)似于 Hibernate 的 UserType。iBatis 本身?yè)碛性摻涌诘谋姸鄬?shí)現類(lèi),如 LongTypeHandler、DateTypeHandler 等,但沒(méi)有為 LOB 類(lèi)型提供對應的實(shí)現類(lèi)。Spring 在 org.springframework.orm.ibatis.support 包中為我們提供了幾個(gè)處理 LOB 類(lèi)型的 TypeHandler 實(shí)現類(lèi):

  • BlobByteArrayTypeHandler:將 BLOB 數據映射為 byte[] 類(lèi)型;
  • BlobSerializableTypeHandler:將 BLOB 數據映射為 Serializable 類(lèi)型的對象;
  • ClobStringTypeHandler:將 CLOB 數據映射為 String 類(lèi)型;

當結果集中包括 LOB 數據時(shí),需要在結果集映射配置項中指定對應的 Handler 類(lèi),下面我們采用 Spring 所提供的實(shí)現類(lèi)對 Post 結果集的映射進(jìn)行配置。


清單 12 . 對 LOB 數據進(jìn)行映射
<?xml version="1.0" encoding="UTF-8" ?>                        <!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"                        "http://ibatis.apache.org/dtd/sql-map-2.dtd">                        <sqlMap namespace="Post">                        <typeAlias alias="post" type="com.baobaotao.domain.Post"/>                        <resultMap id="result" class="post">                        <result property="postId" column="post_id"/>                        <result property="userId" column="user_id"/>                        <result property="postText" column="post_text" ① 讀取 CLOB 類(lèi)型數據                        typeHandler="org.springframework.orm.ibatis.support.ClobStringTypeHandler"/>                        <result property="postAttach" column="post_attach" ② 讀取 BLOB 類(lèi)型數據                        typeHandler="org.springframework.orm.ibatis.support.BlobByteArrayTypeHandler"/>                        </resultMap>                        <select id="getPost" resultMap="result">                        SELECT post_id,user_id,post_text,post_attach,post_time                        FROM t_post  WHERE post_id =#postId#                        </select>                        <insert id="addPost">                        INSERT INTO t_post(user_id,post_text,post_attach,post_time)                        VALUES(#userId#,                        #postText,handler=org.springframework.orm.ibatis.support.ClobStringTypeHandler#, ③                        #postAttach,handler=org.springframework.orm.ibatis.support.BlobByteArrayTypeHandler#, ④                        #postTime#)                        </insert>                        </sqlMap>                        

提示

為每一個(gè) LOB 類(lèi)型字段分別指定處理器并不是一個(gè)好主意,iBatis 允許在 sql-map-config.xml 配置文件中通過(guò) <typeHandler> 標簽統一定義特殊類(lèi)型數據的處理器,如:

<typeHandler jdbcType="CLOB" javaType="java.lang.String" callback="org.springframework.orm.ibatis.support.ClobStringTypeHandler"/>

當 iBatis 引擎從結果集中讀取或更改 LOB 類(lèi)型數據時(shí),都需要指定處理器。我們在 ① 和 ② 處為讀取 LOB 類(lèi)型的數據指定處理器,相似的,在 ③ 和 ④ 處為插入 LOB 類(lèi)型的數據也指定處理器。

此外,我們還必須為 SqlClientMap 提供一個(gè) LobHandler:


清單 13. 將 LobHandler 注入到 SqlClientMap 中
<bean id="lobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler"                        lazy-init="true" />                        <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">                        <property name="dataSource" ref="dataSource" />                        <property name="lobHandler" ref="lobHandler" /> ①設置LobHandler                        <property name="configLocation"                        value="classpath:com/baobaotao/dao/ibatis/sql-map-config.xml" />                        </bean>                        

處理 LOB 數據時(shí),Spring 要求在事務(wù)環(huán)境下工作,所以還必須配置一個(gè)事務(wù)管理器。iBatis 的事務(wù)管理器和 Spring JDBC 事務(wù)管理器相同,此處不再贅述。





回頁(yè)首


小結

本文就 Spring 中如何操作 LOB 數據進(jìn)行較為全面的講解,您僅需簡(jiǎn)單地配置 LobHandler 就可以直接在程序中象一般數據一樣操作 LOB 數據了。對于 ORM 框架來(lái)說(shuō),Spring 為它們分別提供了支持類(lèi),您僅要使用相應的支持類(lèi)進(jìn)行配置就可以了。因此您會(huì )發(fā)現在傳統 JDBC 程序操作 LOB 頭疼的問(wèn)題將變得輕松了許多。

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
spring+Hibernate處理Oracle大字段clob
spirng 對clob blob數據的處理
Spring源代碼分析(三):Spring JDBC
通過(guò)JDBC操縱Oracle數據庫LOB字段的分析
JDBC訪(fǎng)問(wèn)大段文本數據(CLOB)
在Oracle中如何保存長(cháng)文本??一個(gè)表中不能有兩個(gè)CLOB或LONG或BLOB?
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久