如何将unicode数据保存到oracle?

我试图在oracle数据库(10 g)中保存unicode数据(希腊语)。 我创建了一个简单的表:

替代文字http://sofzh.miximages.com/c%23/dvpqnk.png

我知道NVARCHAR2总是使用UTF-16编码,所以它必须适用于所有(人类)语言。

然后我试图在数据库中插入一个字符串。 我在代码中硬编码了字符串(“你好吗?”)。 然后我尝试从数据库中恢复并显示它。

class Program { static string connectionString = ""; static void Main (string[] args) { string textBefore = "Τι κάνεις;"; DeleteAll (); SaveToDatabase (textBefore); string textAfter = GetFromDatabase (); string beforeData = String.Format ("Before: {0}, ({1})", textBefore, ToHex (textBefore)); string afterData = String.Format ("After: {0}, ({1})", textAfter, ToHex (textAfter)); Console.WriteLine (beforeData); Console.WriteLine (afterData); MessageBox.Show (beforeData); MessageBox.Show (afterData); Console.ReadLine (); } static void DeleteAll () { using (var oraConnection = new OracleConnection (connectionString)) { oraConnection.Open (); var command = oraConnection.CreateCommand (); command.CommandText = "delete from UNICODEDATA"; command.ExecuteNonQuery (); } } static void SaveToDatabase (string stringToSave) { using (var oraConnection = new OracleConnection (connectionString)) { oraConnection.Open (); var command = oraConnection.CreateCommand (); command.CommandText = "INSERT into UNICODEDATA (ID, UNICODESTRING) Values (11, :UnicodeString)"; command.Parameters.Add (":UnicodeString", stringToSave); command.ExecuteNonQuery (); } } static string GetFromDatabase () { using (var oraConnection = new OracleConnection (connectionString)) { oraConnection.Open (); var command = oraConnection.CreateCommand (); command.CommandText = "Select * from UNICODEDATA"; var erpReader = command.ExecuteReader (); string s = String.Empty; while (erpReader.Read ()) { string text = erpReader.GetString (1); s += text + ", "; } return s; } } static string ToHex (string input) { string bytes = String.Empty; foreach (var c in input) bytes += ((int)c).ToString ("X4") + " "; return bytes; } } 

以下是不同的输出:

在消息框中发送到数据库之前的文本 : alt text http://sofzh.miximages.com/c%23/2ymdo2u.png

从消息框中的数据库获取后的文本 : 替代文本http://sofzh.miximages.com/c%23/2wmq9a0.png

控制台输出: alt text http://sofzh.miximages.com/c%23/6xz3px.png

请问你能告诉我这里可能做错了什么吗?

我可以看到五个潜在的问题领域:

  1. 你是如何实际将文本导入.NET应用程序的? 如果它是在字符串文字中硬编码,您确定编译器是否为您的源文件采用正确的编码?

  2. 您如何将其发送到数据库可能存在问题。

  3. 如何将其存储在数据库中可能存在问题。

  4. 如何在数据库中获取它可能存在问题。

  5. 您之后如何再次显示它可能会出现问题。

现在区域2-4听起来像是不太可能成为问题而不是1和5.之后你如何显示文本? 你实际上是从.NET中的数据库中取出它,还是使用Toad或类似的东西试图看到它?

如果你再次从.NET写出来,我建议你完全跳过数据库 – 如果你只是显示字符串本身,你看到了什么?

我有一篇文章,您可能会发现调试Unicode问题很有用。 特别是,专注于编码可能出错的每个地方,并确保无论何时“显示”一个字符串,您都会转出精确的Unicode字符(作为整数),这样您就可以检查那些而不仅仅是当前字体想要的内容显示。

编辑:好的,所以数据库涉及问题的某个地方。

强烈建议你删除ASP和HTML之类的东西。 编写一个简单的控制台应用程序, 除了插入字符串并再次获取它之外什么也不做。 使其转发前后各个Unicode字符(整数)。 然后尝试查看数据库中的内容(例如使用Toad)。 我不知道Oracle函数将字符串转换为单个Unicode字符的序列,然后将这些字符转换为整数,但这很可能是我尝试的下一步。

编辑:另外两个建议(很高兴看到控制台应用程序,顺便说一句)。

  1. 指定参数的数据类型,而不是仅为其指定对象。 例如:

     command.Parameters.Add (":UnicodeString", OracleType.NVarChar).Value = stringToSave; 
  2. 考虑使用Oracle自己的驱动程序而不是.NET内置的驱动程序。 无论如何,你可能希望这样做,因为我认为它通常被认为更快更可靠。

您可以使用查询确定数据库对NCHAR使用的字符集:

 SQL> SELECT VALUE 2 FROM nls_database_parameters 3 WHERE parameter = 'NLS_NCHAR_CHARACTERSET'; VALUE ------------ AL16UTF16 

要检查数据库配置是否正确,可以在SQL * Plus中运行以下命令:

 SQL> CREATE TABLE unicodedata (ID NUMBER, unicodestring NVARCHAR2(100)); Table created SQL> INSERT INTO unicodedata VALUES (11, 'Τι κάνεις;'); 1 row inserted SQL> SELECT * FROM unicodedata; ID UNICODESTRING ---------- --------------------------------------------------- 11 Τι κάνεις; 

还有一件事值得注意。

如果您正在使用oracle客户端,并希望在CommandText中包含unicode字符,则应将以下行添加到应用程序的开头:

 System.Environment.SetEnvironmentVariable("ORA_NCHAR_LITERAL_REPLACE", "TRUE"); 

如果需要,这将允许您使用以下语法:

 command.CommandText = "INSERT into UNICODEDATA (ID, UNICODESTRING) Values (11, N'Τι κάνεις;')"; 

经过一些调查,我们走了:

string input =“•”; char s =输入[0];

  //table kuuku with column kuku(nvarchar2(100)) string connString = "your connection"; //CLEAN TABLE using (System.Data.OracleClient.OracleConnection cn = new System.Data.OracleClient.OracleConnection(connString)) { cn.Open(); System.Data.OracleClient.OracleCommand cmd = new System.Data.OracleClient.OracleCommand("delete from kuku ", cn); cmd.ExecuteNonQuery(); cn.Close(); } //INSERT WITH PARAMETER BINDING - UNICODE SAVED using (System.Data.OracleClient.OracleConnection cn = new System.Data.OracleClient.OracleConnection(connString)) { cn.Open(); System.Data.OracleClient.OracleCommand cmd = new System.Data.OracleClient.OracleCommand("insert into kuku (kuku) values(:UnicodeString)", cn); cmd.Parameters.Add(":UnicodeString", System.Data.OracleClient.OracleType.NVarChar).Value = input + " OK" ; cmd.ExecuteNonQuery(); cn.Close(); } //INSERT WITHOUT PARAMETER BINDING - UNICODE NOT SAVED using (System.Data.OracleClient.OracleConnection cn = new System.Data.OracleClient.OracleConnection(connString)) { cn.Open(); System.Data.OracleClient.OracleCommand cmd = new System.Data.OracleClient.OracleCommand("insert into kuku (kuku) values('" +input+" WRONG')", cn); cmd.ExecuteNonQuery(); cn.Close(); } //FETCH RESULT using (System.Data.OracleClient.OracleConnection cn = new System.Data.OracleClient.OracleConnection(connString)) { cn.Open(); System.Data.OracleClient.OracleCommand cmd = new System.Data.OracleClient.OracleCommand("select kuku from kuku", cn); System.Data.OracleClient.OracleDataReader dr = cmd.ExecuteReader(); if(dr.Read()) { string output = (string) dr[0]; char sa = output[0]; } cn.Close(); } } 

PL SQL看起来

在阅读记录时,请尝试

 Encoding utf = Encoding.Default; var utfBytes = odatareader.GetOracleString(0).GetNonUnicodeBytes();//OracleDataReader Console.WriteLine(utf.GetString(utfBytes)); 

解决方案:设置NLS_LANG!

细节:我遇到了同样的问题,实际上与Sergey Bazarnik的调查中描述的情况完全相同。 使用绑定变量它可以工作,没有它就不会。

解决方案是将NLS_LANG设置在适当的位置。 由于我有Windows服务器,我在Windows注册表中将其设置在HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\ORACLE\KEY_OraClient11g_home1

请注意,regitry位置可能不同,因此最简单的方法是在注册表中搜索“ORACLE_HOME”字符串。 还有像Linux,Unix这样的其他系统可以用不同的方式设置它(导出NLS_LANG ……)

在我的情况下,我把"NLS_LANG"="CROATIAN_CROATIA.UTF8" 。 由于我没有该变量集,因此它变为默认值。 更改注册表后,您应重新启动进程。 在我的情况下,我重新启动IIS。

关于它与绑定变量一起工作的原因可能是因为它实际上发生在服务器端,而没有它实际上发生在客户端。 因此,即使该DB可以插入适当的值 – 在此之前,客户端会执行不需要的更正,因为它认为应该这样做。 这是因为NLS_LANG默认为更简单的代码页。 但是,这不会产生有用的任务,而是产生了一个问题(如调查中所示,很难理解)。

如果您有多个oracle版本,请务必更正注册表中的所有版本(在我的情况下,Oracle 10具有有效设置,但Oracle 11根本没有设置NLS_LANG)。