我有一个Oracle数据库,其中存储了一些简体中文的数据值。我创建了一个ASP.net MVC C#网页,该网页应该显示此信息。我使用OdbcConnection
来检索数据,但是当我运行da.Fill(t)
命令时,值返回为“?”
OdbcCommand cmd = new OdbcCommand();
cmd.CommandText = select;
OdbcConnection SqlConn = new OdbcConnection("Driver={Oracle in instantclient_11_2};Dbq=Database;Uid=Username;pwd=password;");
DataTable t = new DataTable();
cmd.Connection = SqlConn;
SqlConn.Open();
OdbcDataAdapter da = new OdbcDataAdapter(cmd);
SqlConn.Close();
da.Fill(t);
return t;
t
有数据,但所有应该是汉字的东西都只是一系列“?????”
1条答案
按热度按时间njthzxwz1#
字符集的问题是相当普遍的,让我试着给予一些一般性的注解。
原则上,您必须考虑四种不同的字符集设置。
1和2:
NLS_CHARACTERSET
和NLS_NCHAR_CHARACTERSET
示例:
AL32UTF8
它们仅在数据库中定义,您可以使用查询它们
这些设置定义了哪些字符(以何种格式)可以存储在您的数据库中-不多也不少。如果您必须在现有数据库中更改它,则需要一些工作(参见Character Set Migration和/或Oracle Database Migration Assistant for Unicode)。
3:
NLS_LANG
示例:
AMERICAN_AMERICA.AL32UTF8
此值仅在您的客户机上定义。NLS_LANG与在数据库中存储字符的能力无关。它用于让Oracle知道您在客户机端使用的字符集。设置NLS_LANG值时(例如AL 32 UTF8),然后您只需告诉Oracle数据库“我的客户端使用字符集AL 32 UTF8”-这并不一定意味着您的客户端真的在使用AL 32 UTF8!(参见下面的#4)
NLS_LANG可以由环境变量
NLS_LANG
定义,也可以由Windows注册表在HKLM\SOFTWARE\Wow6432Node\ORACLE\KEY_%ORACLE_HOME_NAME%\NLS_LANG
(适用于32位)或HKLM\SOFTWARE\ORACLE\KEY_%ORACLE_HOME_NAME%\NLS_LANG
(适用于64位)上定义。根据应用程序的不同,可能还有其他方法可以指定NLS_LANG,但我们还是坚持使用基本方法。如果未提供NLS_LANG值,Oracle将默认为AMERICAN_AMERICA.US7ASCII
NLS_LANG的格式为
NLS_LANG=language_territory.charset
。NLS_LANG的{charset}部分不显示在任何系统表或视图中。NLS_LANG定义的所有组件都是可选的,因此以下定义都有效:一米十氮一x,一米十一氮一x,一米十二氮一x,一米十三氮一x,一米十四氮一x。如上所述,
NLS_LANG
的{charset}部分在数据库的任何系统表/视图或任何函数中都不可用。严格地说,这是真的,但是您可以运行以下查询:它应该从当前的
NLS_LANG
设置返回字符集-但是根据我的经验,该值通常为NULL或Unknown
,即不可靠。在这里找到更多非常有用的信息:NLS_LANG FAQ
请注意,某些技术不使用
NLS_LANG
,因此那里的设置没有任何效果,例如:NLS_LANG
。它只区分.NET区域设置。(请参阅.NET开发人员指南的数据提供程序)4:终端、应用程序或
.sql
文件编码的“真实的”字符集示例:
UTF-8
如果您使用终端程序(即SQL*plus或isql),则可以使用命令
chcp
查询代码页,在Unix/Linux上,等效命令为locale charmap
或echo $LANG
。您可以从此处获得所有Windows代码页标识符的列表:注意,对于UTF-8(chcp 65001
),存在一些问题,请参见this discussion。如果你使用
.sql
文件和TOAD或SQL-Developer这样的编辑器,你必须检查保存选项。通常你可以选择UTF-8
,ANSI
,ISO-8859-1
等值。ANSI
表示Windows ANSI代码页,通常是CP1252
,你可以在HKLM\SYSTEM\ControlSet001\Control\Nls\CodePage\ACP
或这里检查你的注册表:National Language Support (NLS) API Reference如何设置所有这些值?
最重要的一点是匹配
NLS_LANG
和您的“真实的”字符集的终端,分别。应用程序或编码的.sql
文件一些常见的配对是:
WE8MSWIN1252
WE8ISO8859P1
WE8ISO8859P15
AL32UTF8
或者运行此查询以获取更多信息:
型
有些技术可以让你的生活更轻松,例如ODP .NET(unmanged driver)或Oracle的ODBC驱动程序会自动继承
NLS_LANG
值的字符集,因此上述条件始终为真。是否需要将客户端NLS_LANG值设置为等于数据库
NLS_CHARACTERSET
值?不,不一定!例如,如果您有数据库字符集
NLS_CHARACTERSET=AL32UTF8
和客户端字符集NLS_LANG=.ZHS32GB18030
,那么它将毫无问题地工作(前提是您的客户端确实使用GB 18030),尽管这些字符集完全不同。GB18030是中文常用的字符集,与UTF-8
一样,它支持所有Unicode字符。如果您有,例如
NLS_CHARACTERSET=AL32UTF8
和NLS_LANG=.WE8ISO8859P1
,它也可以工作(同样,假设您的客户端确实使用ISO-8859-P1)。但是,数据库可能存储您的客户端无法显示的字符,而客户端将显示一个占位符(例如¿
)。无论如何,如果合适,匹配NLS_LANG和NLS_CHARACTERSET值是有益的。如果它们相等,您可以确保任何可能存储在数据库中的字符也可以显示,并且您在终端中输入或写入.sql文件的任何字符也可以存储在数据库中,并且不会被占位符替代。
补充
很多时候你会读到像“NLS_LANG字符集必须与你的数据库字符集相同”这样的建议(也在SO上)。这根本不是真的,这是一个流行的神话!
下面就是证明:
客户机和数据库字符集都是
AL32UTF8
,但字符不匹配。原因是,我的cmd.exe
以及SQL*Plus使用Windows CP 1252。因此,我必须相应地设置NLS_LANG:再考虑一下这个例子:
您需要为单个语句的
NLS_LANG
设置两个不同的值-这是不可能的。另请参见如果我们有US 7ASCII字符集,为什么它允许我们存储非ASCII字符?或者NLS_NCHAR_CHARACTERSET和NLS_CHARACTERSET for Oracle之间的区别