posts - 40,  comments - 187,  trackbacks - 0

          以前寫過的一篇博文中提到了出現(xiàn)“ORA-01461: 僅可以為插入 LONG 列的 LONG 值賦值”的原因,并給出了原因和解決方法,在這裡回顧一下。(詳見 當遇到“數(shù)據(jù)大小超出此類型的最大值”和“僅可以為插入 LONG 列的 LONG 值賦值”時...? )

          當時的環(huán)境:?
          數(shù)據(jù)庫:Oracle 9i
          數(shù)據(jù)庫字段類型:varchar2(4000)
          輸入漢字:大于1000字

          原因:
          ?? 我的數(shù)據(jù)庫字符集應(yīng)該是UTF-8的,對于UTF-8或歐洲的某些字符集,oracle在存儲時,對于一個字符需要2個或3個字節(jié)的存儲空間,雖然表定義中為varchar2(4000),但是其實該字段的data_length為其2倍或3倍長。這種情況下oracle會把data_length長度超過4000的當做LONG型處理,你的表中有兩個這樣的字段,插入數(shù)據(jù)時相當于同時操作2個LONG字段,所以報錯。

          當時的解決辦法:建議減小字段長度或拆分。實在需要的,可以轉(zhuǎn)而采用CLOB字段類型。


          現(xiàn)在的環(huán)境:

          開發(fā)框架:Spring 2.0.6 + Hibernate 3.2
          數(shù)據(jù)庫:Oracle 9i
          數(shù)據(jù)庫字段類型:CLOB
          輸入字節(jié):1000 ~ 2000

          現(xiàn)在的問題:
          現(xiàn)在的項目中我采用了CLOB字段類型,但又遇到了這個錯誤。當我對Oracle數(shù)據(jù)庫中的CLOB字段進入insert或update操作的時候,后臺出現(xiàn) java.sql.SQLException:?? ORA-01461: 僅可以為插入 LONG 列的 LONG 值賦值。這個錯誤的特點是,當插入的數(shù)據(jù)長度小於1000字節(jié)或者大於2000字節(jié)時都不會報錯,一旦插入的數(shù)據(jù)長度在1000 ~ 2000之間時就會報錯。經(jīng)過google一番之後,ORA-01461錯誤是一個經(jīng)典問題了,有人認為是CLOB字段本身的問題。

          解決方法:

          方法1:
          采用Oracle 10g最新的ojdbc14.jar驅(qū)動替換原有的驅(qū)動即可。試過了這種方法,但是并沒有生效。

          方法2:

          1. Hibernate實體對象中的數(shù)據(jù)成員類型為String,映射的數(shù)據(jù)庫字段類型為org.springframework.orm.hibernate.support.ClobStringType。實例如下:
          @SuppressWarnings("serial")
          @Entity
          @Table(name?
          =?"GUIDE")
          //@Cache(usage?=?CacheConcurrencyStrategy.READ_WRITE)
          public?class?Guide?{
          ????
          ????@Type(type?
          =?"org.springframework.orm.hibernate3.support.ClobStringType")
          ????
          private?String?content;?//內(nèi)容

          ?????????
          //get?&?set?
          }


          2. 如果使用Spring的這個Clob類型就需要在applicationContext.xml中的sessionFactory bean里注入oracleLobHandler bean。下面給出Oracle數(shù)據(jù)庫的LobHandler配置:
          .
          < bean? id ="oracleLobHandler" ?
          ??????class
          ="org.springframework.jdbc.support.lob.OracleLobHandler" ?
          ??????lazy-init
          ="true" > ??
          ????
          < property? name ="nativeJdbcExtractor" ?ref ="nativeJdbcExtractor" ? />
          </ bean > ????
          ?
          < bean? id ="nativeJdbcExtractor" ???????class ="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor"
          ??????lazy-init
          ="true" ? /> ??

          <!-- ?Hibernate?SessionFactory? -->
          < bean? id ="sessionFactory" ?class ="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" >
          ????
          < property? name ="dataSource" ?ref ="dataSource" ? />
          ????
          < property? name ="configLocation" ?value ="classpath:hibernate/hibernate.cfg.xml" ? />
          ????
          < property? name ="hibernateProperties" >
          ????????
          < value >
          ??????????
          ????????
          </ value >
          ????
          </ property >
          ????
          < property? name ="lobHandler" ?ref ="oracleLobHandler" ? />
          </ bean >
          .

          LobHandler 需要訪問本地 JDBC 對象,這一任務(wù)委托給 NativeJdbcExtractor Bean 來完成,NativeJdbcExtractor是一個本地JDBC對象抽取器,因此我們?yōu)?LobHandler 注入了一個 nativeJdbcExtractor。最后,我們把 lobHandler Bean 注入到需要進行 LOB 數(shù)據(jù)訪問操作的sessionFactory Bean中或者直接注入到dao Bean中去。

          大家可能已經(jīng)注意到 nativeJdbcExtractor 和 oracleLobHandler Bean 都設(shè)置為 lazy-init="true",這是因為 nativeJdbcExtractor 需要通過運行期的反射機制獲取底層的JDBC 對象,所以需要避免在 Spring 容器啟動時就實例化這兩個Bean。
          如果底層數(shù)據(jù)庫是 DB2、SQL Server、MySQL 等非 Oracle 的其它數(shù)據(jù)庫,則只要簡單配置一個 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 對象,由于并不需要訪問數(shù)據(jù)庫驅(qū)動本地的 JDBC 對象,所以它不需要 NativeJdbcExtractor 的幫助。

          ??? 采用第二種方法即可解決我所遇到的問題,如果再見到“ORA-01461: 僅可以為插入 LONG 列的 LONG 值賦值”時,希望這個方法能夠幫您順利拿下ORA-01461。



          PS:給出Oracle下幾種大容量字段類型的解釋
          LONG: 可變長的字符串數(shù)據(jù),最長2G,LONG具有VARCHAR2列的特性,可以存儲長文本一個表中最多一個LONG列
          LONG RAW: 可變長二進制數(shù)據(jù),最長2G
          CLOB:? 字符大對象Clob 用來存儲單字節(jié)的字符數(shù)據(jù)
          NCLOB: 用來存儲多字節(jié)的字符數(shù)據(jù)
          BLOB: 用于存儲二進制數(shù)據(jù)
          BFILE: 存儲在文件中的二進制數(shù)據(jù),這個文件中的數(shù)據(jù)只能被只讀訪。但該文件不包含在數(shù)據(jù)庫內(nèi)。bfile字段實際的文件存儲在文件系統(tǒng)中,字段中存儲的是文件定位指針.bfile對oracle來說是只讀的,也不參與事務(wù)性控制和數(shù)據(jù)恢復(fù)。
            
          其中CLOB,NCLOB,BLOB都是內(nèi)部的LOB(Large Object)類型,最長4G,沒有LONG只能有一列的限制。要保存圖片、文本文件、Word文件各自最好采用那種數(shù)據(jù)類型呢?BLOB最好,LONG RAW也不錯,但Long是oracle將要廢棄的類型,因此建議用BLOB。


          ??????????????????????????????????????????????????????????????????????????? THE END
          ?
          posted on 2008-05-06 10:30 小立飛刀 閱讀(32745) 評論(5)  編輯  收藏 所屬分類: SpringHibernate 、Database

          FeedBack:
          # re: 又見“ORA-01461: 僅可以為插入 LONG 列的 LONG 值賦值”![未登錄]
          2009-08-25 17:51 | wolf
          放屁,我插入1都不行,1大于1000嗎??  回復(fù)  更多評論
            
          # re: 又見“ORA-01461: 僅可以為插入 LONG 列的 LONG 值賦值”!
          2009-08-28 16:11 | 小立飛刀
          @wolf
          這位網(wǎng)友,請您說話干凈一點,有問題可以提,我們一起探討,希望不要再有這樣的言語。

          “我插入1都不行,1大于1000嗎?? ” 沒明白您的問題,再說得詳細點如何  回復(fù)  更多評論
            
          # re: 又見“ORA-01461: 僅可以為插入 LONG 列的 LONG 值賦值”![未登錄]
          2010-02-05 11:10 | gongmingwind
          您好,我也是在使用hibernate時遇到的這個問題,按照您說的方法試驗了下,好像還是不行,使用的驅(qū)動是ojdbc14-10.2.0.2.0.jar;后來改成:ojdbc14-10.2.0.3.0.jar問題就解決了,所以可能是驅(qū)動的問題,故將解決方法寫下,共同探討.  回復(fù)  更多評論
            
          # re: 又見“ORA-01461: 僅可以為插入 LONG 列的 LONG 值賦值”!
          2010-02-08 09:54 | 小立飛刀
          @gongmingwind
          嗯,多謝,看來是我的驅(qū)動版本沒對上,呵呵。  回復(fù)  更多評論
            
          # re: 又見“ORA-01461: 僅可以為插入 LONG 列的 LONG 值賦值”!
          2011-04-24 22:27 | hourm
          @gongmingwind
          正解,確實是驅(qū)動得問題,另外一樓確實談吐不雅,請注意,樓主很有風(fēng)度
            回復(fù)  更多評論
            
          <2010年2月>
          31123456
          78910111213
          14151617181920
          21222324252627
          28123456
          78910111213

          生存或毀滅,這是個必答之問題:是否應(yīng)默默的忍受坎苛命運之無情打擊,還是應(yīng)與深如大海之無涯苦難奮然為敵,并將其克服。此二抉擇,究竟是哪個較崇高?

          常用鏈接

          留言簿(12)

          隨筆分類(43)

          相冊

          收藏夾(7)

          朋友的博客

          電子資料

          搜索

          •  

          積分與排名

          • 積分 - 302745
          • 排名 - 192

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 镇沅| 洱源县| 卫辉市| 商河县| 融水| 理塘县| 新竹县| 浮山县| 平陆县| 阳谷县| 桐乡市| 怀宁县| 鄂伦春自治旗| 方城县| 新疆| 内黄县| 安新县| 花垣县| 宜兴市| 赤水市| 颍上县| 宁明县| 东辽县| 公安县| 新河县| 阜南县| 沐川县| 龙里县| 贞丰县| 会理县| 阿坝县| 梁河县| 姚安县| 康定县| 鹿邑县| 宁海县| 兴和县| 伊通| 石屏县| 洛宁县| 四子王旗|