无法使用 cx-Oracle 插入 Unicode

Posted

技术标签:

【中文标题】无法使用 cx-Oracle 插入 Unicode【英文标题】:Cannot Insert Unicode Using cx-Oracle 【发布时间】:2012-12-23 17:06:50 【问题描述】:

我在将 unicode 插入 Oracle 架构时遇到问题,我认为数据库是 Oracle 11g 实例,但目前还不确定。我在 OS X 10.6.8 上使用 python 2.6.1(这是 python 的系统版本)并使用从 sourceforge.net 下载的 cx-Oracle 驱动程序模块 5.1 版,构建并安装到 virtualenv 1.6.1 实例网站包可见。我的脚本如下

  import cx_Oracle

  connection = cx_Oracle.connect(
      "<name>/<password>@<host>/<service-name>"
      )
  cursor = connection.cursor()
  result = cursor.execute(u"create table UNICODE_TEST (id NUMBER(6), text NCLOB not NULL)")

  raw_text = open("test.txt",'r').read()
  if isinstance(raw_text,str):
      raw_text = raw_text.decode("utf_8")

  statement = u"insert into UNICODE_TEST (id, text) values (1,'%s')" % raw_text
  result = cursor.execute(statement)

我创建了一个连接,创建了游标,执行了一个语句来创建一个带有 NUMBER 和 NCLOB 类型的 id 和文本字段的测试表。 我打开一个文件,其中包含我知道的以 UTF-8 编码的文本,将字符串解码为 un​​icode。 在 unicode 字符串中创建一个插入语句并执行该语句,结果就是这个错误。

  Traceback (most recent call last):
    File "unicode-test.py", line 19, in <module>
      result = cursor.execute(statement)
  UnicodeEncodeError: 'ascii' codec can't encode character u'\u2122' in position 170: ordinal not in range(128)

在将我的语句插入 Oracle 架构之前,有东西试图将其编码为 ASCII。所以我开始四处寻找以更好地了解 cx-Oracle 如何处理 unicode,并在我从 sourceforge.net 下载的 cx-Oracle 源代码的 HISTORY.txt 中找到了这一点

从 5.0.4 更改为 5.1 1) 删除对 UNICODE 模式的支持和 允许 Unicode 在 任何地方都可以传入一个字符串。这意味着字符串将是 使用 NLS_LANG 环境的值传递给 Oracle Python 3.x 中的变量也是如此。这样做消除了一堆问题 通过使用 UNICODE 模式发现的,并且还删除了不必要的 Python 2.x 中限制 Unicode 不能用于连接字符串 或 SQL 语句,例如。 ...

我的假设是 NLS_LANG 环境变量设置为“ascii”或其他等效变量,因此我尝试将 NLS_LANG 设置为“AL32UTF8”,我认为这是 unicode 的正确值,并在创建连接之前设置新值。

  os.environ["NLS_LANG"] = "AL32UTF8"
  connection = cx_Oracle.connect(
      "<user>/<password>@<host>/<service-name>"
      )
  cursor = connection.cursor()
  ...

但我收到此错误。

  Traceback (most recent call last):
    File "unicode-test.py", line 11, in <module>
      "<user>/<password>@<host>/<service-name>"
  cx_Oracle.DatabaseError: ORA-12705: Cannot access NLS data files or invalid environment specified

所以看起来我无法篡改 NLS_LANG 值。

这是我目前的问题。我是否遗漏了一些简单的东西,例如不正确的列类型?是 cx-Oracle 驱动程序的问题吗?在构建 cx-Oracle 模块时,我是否需要设置“WITH_UNICODE”环境变量,我该怎么做?是 Oracle 实例的问题吗?我对 Oracle 的经验很少,也从未与 Oracle 和 python 一起工作过。我已经花了两天时间来解决这个问题,并希望在我去 DBA 小组之前更好地了解问题所在。

谢谢,

【问题讨论】:

【参考方案1】:

设置环境变量是正确的方法,但“AL32UTF8”不是 NLS_LANG 的正确值。要获得在您的 Oracle 实例中使用的 NLS_LANG 的正确值,请执行

SELECT USERENV ('language') FROM DUAL  

【讨论】:

感谢您的回复,我终于收到了我的 DBA 的回复。对于我们的 11gR2 安装,CHARACTER SET 是“WE8MSWIN1252”,NATIONAL CHARACTER SET 是“AL16UTF16”。似乎驱动程序没有正确检测上述变量中​​的编码集。检查连接上的 'encoding' 和 'nencoding' 属性在这两种情况下都会产生 'US-ASCII' 是不正确的。尝试将 NLS_LANG 转换为 'AL16UTF16' 时,我仍然得到相同的 DatabaseError,因为我与架构的连接已被删除(并且也将在生产中)解释了为什么无法访问这些文件。 在我的情况下,上述查询的结果是“AMERICAN_AMERICA.US7ASCII”。但是,一旦我的 NLS_LANG 设置为“_.AL32UTF8”(不带引号),我的 Unicode 插入就开始正常工作了。 我的上述查询结果是 AMERICAN_AMERICA.WE8MSWIN1252。 @davidjb,您如何将其设置为不带引号的值。你在你的作用域中导入了什么来获得它? 我发现this page 的代码为os.environ["NLS_LANG"] = ".AL32UTF8",这对我有用。注意前导点,但不要下划线。

以上是关于无法使用 cx-Oracle 插入 Unicode的主要内容,如果未能解决你的问题,请参考以下文章

鼠标右键插入unicode控制字符怎么弄出来?

无法区分 mysql 和 phpMyAdmin 中由不同 Unicode 字母组成的单词

MacBook m1 pro python cx-oracle提示不是x86如何处理?

将 Unicode 字符插入 JavaScript

Hibernate + JPA + jTDS + SQL Server = Unicode 问题

phpMyAdmin 不会在数据库中正确显示或插入 Unicode 字符