以前寫過的一篇博文中提到了出現“ORA-01461: 僅可以為插入 LONG 列的 LONG 值賦值”的原因,并給出了原因和解決方法,在這裡回顧一下。(詳見 當遇到“數據大小超出此類型的最大值”和“僅可以為插入 LONG 列的 LONG 值賦值”時...? )
當時的環境:?
數據庫:Oracle 9i
數據庫字段類型:varchar2(4000)
輸入漢字:大于1000字
原因:
?? 我的數據庫字符集應該是UTF-8的,對于UTF-8或歐洲的某些字符集,oracle在存儲時,對于一個字符需要2個或3個字節的存儲空間,雖然表定義中為varchar2(4000),但是其實該字段的data_length為其2倍或3倍長。這種情況下oracle會把data_length長度超過4000的當做LONG型處理,你的表中有兩個這樣的字段,插入數據時相當于同時操作2個LONG字段,所以報錯。
當時的解決辦法:建議減小字段長度或拆分。實在需要的,可以轉而采用CLOB字段類型。
現在的環境:
開發框架:Spring 2.0.6 + Hibernate 3.2
數據庫:Oracle 9i
數據庫字段類型:CLOB
輸入字節:1000 ~ 2000
現在的問題:
數據庫字段類型:CLOB
輸入字節:1000 ~ 2000
現在的問題:
現在的項目中我采用了CLOB字段類型,但又遇到了這個錯誤。當我對Oracle數據庫中的CLOB字段進入insert或update操作的時候,后臺出現 java.sql.SQLException:?? ORA-01461: 僅可以為插入 LONG 列的 LONG 值賦值。這個錯誤的特點是,當插入的數據長度小於1000字節或者大於2000字節時都不會報錯,一旦插入的數據長度在1000 ~ 2000之間時就會報錯。經過google一番之後,ORA-01461錯誤是一個經典問題了,有人認為是CLOB字段本身的問題。
解決方法:
方法1:
采用Oracle 10g最新的ojdbc14.jar驅動替換原有的驅動即可。試過了這種方法,但是并沒有生效。
方法2:
1. Hibernate實體對象中的數據成員類型為String,映射的數據庫字段類型為org.springframework.orm.hibernate.support.ClobStringType。實例如下:














2. 如果使用Spring的這個Clob類型就需要在applicationContext.xml中的sessionFactory bean里注入oracleLobHandler bean。下面給出Oracle數據庫的LobHandler配置:


























LobHandler 需要訪問本地 JDBC 對象,這一任務委托給 NativeJdbcExtractor Bean 來完成,NativeJdbcExtractor是一個本地JDBC對象抽取器,因此我們為 LobHandler 注入了一個 nativeJdbcExtractor。最后,我們把 lobHandler Bean 注入到需要進行 LOB 數據訪問操作的sessionFactory Bean中或者直接注入到dao Bean中去。
大家可能已經注意到 nativeJdbcExtractor 和 oracleLobHandler Bean 都設置為 lazy-init="true",這是因為 nativeJdbcExtractor 需要通過運行期的反射機制獲取底層的JDBC 對象,所以需要避免在 Spring 容器啟動時就實例化這兩個Bean。
如果底層數據庫是 DB2、SQL Server、MySQL 等非 Oracle 的其它數據庫,則只要簡單配置一個 DefaultLobHandler 就可以了,如下所示:
<bean?id="defaultLobHandler"?
class="org.springframework.jdbc.support.lob.DefaultLobHandler"?
lazy-init="true"/>
<bean?id="testDao"?class="com.test.dao.jdbc.TestJdbcDao">
???<property?name="lobHandler"?ref="?defaultLobHandler"/>?
<property?name="jdbcTemplate"?ref="jdbcTemplate"?/>
</bean>

DefaultLobHandler 只是簡單地代理標準 JDBC 的 PreparedStatement 和 ResultSet 對象,由于并不需要訪問數據庫驅動本地的 JDBC 對象,所以它不需要 NativeJdbcExtractor 的幫助。








DefaultLobHandler 只是簡單地代理標準 JDBC 的 PreparedStatement 和 ResultSet 對象,由于并不需要訪問數據庫驅動本地的 JDBC 對象,所以它不需要 NativeJdbcExtractor 的幫助。
??? 采用第二種方法即可解決我所遇到的問題,如果再見到“ORA-01461: 僅可以為插入 LONG 列的 LONG 值賦值”時,希望這個方法能夠幫您順利拿下ORA-01461。
PS:給出Oracle下幾種大容量字段類型的解釋
LONG: 可變長的字符串數據,最長2G,LONG具有VARCHAR2列的特性,可以存儲長文本一個表中最多一個LONG列
LONG RAW: 可變長二進制數據,最長2G
CLOB:? 字符大對象Clob 用來存儲單字節的字符數據
NCLOB: 用來存儲多字節的字符數據
BLOB: 用于存儲二進制數據
BFILE: 存儲在文件中的二進制數據,這個文件中的數據只能被只讀訪。但該文件不包含在數據庫內。bfile字段實際的文件存儲在文件系統中,字段中存儲的是文件定位指針.bfile對oracle來說是只讀的,也不參與事務性控制和數據恢復。
其中CLOB,NCLOB,BLOB都是內部的LOB(Large Object)類型,最長4G,沒有LONG只能有一列的限制。要保存圖片、文本文件、Word文件各自最好采用那種數據類型呢?BLOB最好,LONG RAW也不錯,但Long是oracle將要廢棄的類型,因此建議用BLOB。
??????????????????????????????????????????????????????????????????????????? THE END
LONG RAW: 可變長二進制數據,最長2G
CLOB:? 字符大對象Clob 用來存儲單字節的字符數據
NCLOB: 用來存儲多字節的字符數據
BLOB: 用于存儲二進制數據
BFILE: 存儲在文件中的二進制數據,這個文件中的數據只能被只讀訪。但該文件不包含在數據庫內。bfile字段實際的文件存儲在文件系統中,字段中存儲的是文件定位指針.bfile對oracle來說是只讀的,也不參與事務性控制和數據恢復。
其中CLOB,NCLOB,BLOB都是內部的LOB(Large Object)類型,最長4G,沒有LONG只能有一列的限制。要保存圖片、文本文件、Word文件各自最好采用那種數據類型呢?BLOB最好,LONG RAW也不錯,但Long是oracle將要廢棄的類型,因此建議用BLOB。
??????????????????????????????????????????????????????????????????????????? THE END
?