日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

Oracle中Clob类型处理解析

發布時間:2024/8/26 综合教程 27 生活家
生活随笔 收集整理的這篇文章主要介紹了 Oracle中Clob类型处理解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最近利用NHibernate映射類型為Clob字段在插入數據時發現當字符的字節數(一個半角字符一個字節,一個全角字符兩個字節)在2000-4000之間時報錯(ORA-01461:僅可以插入LONG列的LONG值賦值)。經過不斷查找資料和自己的試驗該問題終于得到解決,下邊我將自己的心得給大家做一個分享。

準備

系統環境xp+.net2.0+oracle9i

表結構(由于是測試,表結構隨便建了一張)XX

字段名

類型

ID

VARCHAR2(70)

TEST

CLOB

測試

方式1:直接將CLOB的值拼寫在SQL語句中。

代碼:

stringid=Guid.NewGuid().ToString();
OracleCommandcmd=Conn.CreateCommand();
cmd.CommandText="insertintoxx(id,test)values('"+id+"','"+data+"')";//data是一個變量,存儲你要插入的字符串
cmd.ExecuteNonQuery();

情況分析:

當data的長度大于4000時報錯(ORA-01704:文字字符串過長),小于或等于4000時正常插入。

原因分析:

之所以會出現長度大于4000時報錯,是因為Oracle中有SQL語句中兩個單引號之間的字符數不能大于4000的限制。'"+ data +"'data在sql語句之間,當data的值大于4000個字節時就會報錯。

解決辦法:

這種方式比較棘手,但有更好的方式,下邊會講到。

方式2:采用參數形式。

代碼:

stringid=Guid.NewGuid().ToString();
OracleCommandcmd=Conn.CreateCommand();
cmd.CommandText="insertintoxx(id,test)values('"+id+"',:p1)";
OracleParameterp1=newOracleParameter("p1",OracleType.Clob);
p1.Value=data;//data是一個變量,存儲你要插入的字符串
cmd.Parameters.Add(p1);
cmd.ExecuteNonQuery();

情況分析:

采用這種方式能夠正常插入。所以推薦用這種方式。

原因分析:

解決辦法:

方式3:采用參數形式,但是參數類型寫為OracleType. NVarChar

代碼:

stringid=Guid.NewGuid().ToString();
OracleCommandcmd=Conn.CreateCommand();
cmd.CommandText="insertintoxx(id,test)values('"+id+"',:p1)";
OracleParameterp1=newOracleParameter("p1",OracleType.NVarChar);
p1.Value=data;//data是一個變量,存儲你要插入的字符串
cmd.Parameters.Add(p1);
cmd.ExecuteNonQuery();

情況分析:

為什么要寫這種方式,因為這種方式和采用NHibernate的方式很相似,先看看在這種方式會產生什么情況。當data的字節數在0-2000之間時正常插入,大于4000時也正常插入,但在2000-4000時則失敗,報錯(ORA-01461:僅可以插入LONG列的LONG值賦值)

原因分析:

沒有采用對應的Oracle類型。

解決辦法:

采用OracleType.Clob

下邊采用NHibernate插入數據,NHibernate具體怎用不在本次討論范圍。

NHibernate采用的版本為1.2.1.4000。

下邊大至把簡要配置寫下。

App.config

<?xmlversion="1.0"encoding="utf-8"?>

<configuration>

<configSections>

<sectionname="nhibernate"type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089"/>

</configSections>

<nhibernate>

<addkey="hibernate.connection.provider"value="NHibernate.Connection.DriverConnectionProvider"/>

<addkey="hibernate.connection.driver_class"value="NHibernate.Driver.OracleClientDriver"/>

<addkey="hibernate.connection.isolation"value="ReadCommitted"/>

<addkey="hibernate.dialect"value="NHibernate.Dialect.Oracle9Dialect"/>

<addkey="hibernate.connection.connection_string"

value="Data Source=Orcl_192.168.0.232;User ID =icqs_test;Password=icqs_test"/>

<addkey="show_sql"value="true"/>

<add

key="hibernate.adonet.batch_size"

value="100"

/>

</nhibernate>

</configuration>

xx.cs

usingSystem;
usingSystem.Collections.Generic;
usingSystem.Text;

namespaceTest.Enties
{
[Serializable]
publicclassXx
{
publicXx()
{
}

privatestringid;

publicvirtualstringId
{
get{returnid;}
set{id=value;}
}

publicvirtualstringTest
{
get{returntest;}
set{test=value;}
}

privatestringtest;

}
}

xx.hbm.xml

<?xmlversion="1.0"?>

<hibernate-mappingxmlns="urn:nhibernate-mapping-2.2"namespace="Test.Enties"assembly="Test">

<classname="Xx"table="xx"lazy="true">

<idname="Id"column="id"type="String">

<generatorclass="assigned"/>

</id>

<propertycolumn="test"type="StringClob"name="Test"length="2147483647"/>

</class>

</hibernate-mapping>

說明:

<addkey="hibernate.connection.driver_class"value="NHibernate.Driver.OracleClientDriver"/>這里的驅動用的NHibernate.Driver.OracleClientDriver,其實是對微軟的OracleClient的封裝啦,其實內部還是調用微軟的OracleClient的東東。引用System.Data.OracleClient.dll即可OracleClient。

做好上邊的配置后,便有了以下的方式

方式4:采用NHibernate

代碼:

stringid=Guid.NewGuid().ToString();
Xxxx=newXx();
xx.Test=data;//data是一個變量,存儲你要插入的字符串
xx.Id=id;
ISessionsession=SessionFactory.OpenSession();
session.Save(xx);
session.Flush();

情況分析:

當data的字節數在0-2000之間時正常插入,大于4000時也正常插入,但在2000-4000時則失敗,報錯(ORA-01461:僅可以插入LONG列的LONG值賦值).情況和方式3的情況一樣。

原因分析:

NHibernate在用OracleClient映射StringClob時,設置參數類型為OracleType.NVarChar,導致插入有BUG。網上有人推測是OracleClient的BUG所致,理由是換用OracleDataAccess即可解決。

為什么說NHibernate將參數類型設置為OracleType.NVarChar呢?看下邊

找到NHibernate的源代碼,把它加入你的工程。記得不要移動NHibernate位置直接加入工程,直接在NHibernate的安裝目錄引用進來。

2. 在Test解決方案中添加NHibernate的項目引用。

經過上邊兩個步驟我們就可以跟蹤調試NHibernate了

跟蹤代碼session.Save(xx);看看它究竟做了啥。

當我們跟進CommandSetBatchingBatcher時,可以得到以下信息(如圖中的調試信息)。CurrentBatch類型是OracleClientCommandSet,OracleClientCommandSet看源碼得知是對微軟的OracleCommandSet的封裝,因為這個類internal sealed class,所以我們的程序里是找不到這個類的,不過NHibernate通過反射使用了它的功能。OracleCommandSet可能用作批處理的,就是一次處理多個SQL語句的,不是太了解,誰知道請指教。

CommandSetBatchingBatcher的源碼

internalclassOracleClientCommandSet:DbCommandSet<OracleConnection,OracleCommand>
{
privatestaticSystem.TypeoracleCmdSetType;

staticOracleClientCommandSet()
{
AssemblysysDataOracleClient=Assembly.Load("System.Data.OracleClient,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089");
oracleCmdSetType=sysDataOracleClient.GetType("System.Data.OracleClient.OracleCommandSet");
Debug.Assert(oracleCmdSetType!=null,"CouldnotfindOracleCommandSet!");
}

protectedoverrideobjectCreateInternalCommandSet()
{
returnActivator.CreateInstance(oracleCmdSetType,true);
}

}

跟蹤CurrentBatch可以看到

CommandText:

declare

type refcursortype is ref cursor;

begin

INSERT INTO z3 (test, id) VALUES (:p2, :p3);

:r1_4 := sql%rowcount;

end;

這里的p2就是我們的Clob類型字段的參數啦。

再看p2的OracleType是NVarChar,是不是有點明白啦,對了,跟我們3一樣,參數類型錯掉了。

解決辦法:

使用NHibernate的自定義類型,不是太會,幸好網上有高人提供代碼,在此想高人致謝。這樣我們通過自定義類型來設置正確的OracleType即可。在項目中添加兩個類。

PatchForOracleLobField.cs

usingSystem;
usingSystem.Collections.Generic;
usingSystem.Data;
usingSystem.Text;
usingNHibernate;
usingNHibernate.SqlTypes;
usingNHibernate.UserTypes;

namespaceTest.type
{
publicabstractclassPatchForOracleLobField:IUserType
{
publicPatchForOracleLobField()
{
}

publicboolIsMutable
{
get{returntrue;}
}

publicSystem.TypeReturnedType
{
get{returntypeof(String);}
}

publicSqlType[]SqlTypes
{
get
{
returnnewSqlType[]{NHibernateUtil.String.SqlType};
}
}

publicobjectDeepCopy(objectvalue)
{
returnvalue;
}

publicnewboolEquals(objectx,objecty)
{
returnx==y;
}

publicintGetHashCode(objectx)
{
returnx.GetHashCode();
}

publicobjectAssemble(objectcached,objectowner)
{
returnDeepCopy(cached);
}

publicobjectDisassemble(objectvalue)
{
returnDeepCopy(value);
}

publicobjectNullSafeGet(IDataReaderrs,string[]names,objectowner)
{
returnNHibernate.NHibernateUtil.StringClob.NullSafeGet(rs,names[0]);
}

publicabstractvoidNullSafeSet(IDbCommandcmd,objectvalue,intindex);

publicobjectReplace(objectoriginal,objecttarget,objectowner)
{
returnoriginal;
}

}
}

OracleClobField.cs

usingSystem;
usingSystem.Collections.Generic;
usingSystem.Data;
usingSystem.Data.OracleClient;
usingSystem.Text;

namespaceTest.type
{
publicclassOracleClobField:PatchForOracleLobField
{
publicoverridevoidNullSafeSet(IDbCommandcmd,objectvalue,intindex)
{
if(cmdisOracleCommand)
{
//CLob、NClob類型的字段,存入中文時參數的OracleDbType必須設置為OracleDbType.Clob
//否則會變成亂碼(Oracle10gclient環境)
OracleParameterparam=cmd.Parameters[index]asOracleParameter;
if(param!=null)
{
param.OracleType=OracleType.Clob;// 關鍵就這里啦
param.IsNullable=true;
}
}
NHibernate.NHibernateUtil.StringClob.NullSafeSet(cmd,value,index);
}
}
}

然后在映射文件中修改類型即可。

Com.Dic.Icqs.Entities.Type.OracleClobField,Com.Dic.Icqs.Entities

修改前:

<propertycolumn="test"type="StringClob"name="Test"length="2147483647"/>

修改后:

<propertycolumn="test"type="Test.type.OracleClobField,Test"name="Test"length="2147483647"/>

Test.type.OracleClobField是類的完整名,Test即OracleClobField所在的程序集。

總結

以上是生活随笔為你收集整理的Oracle中Clob类型处理解析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。