使用Doctrine2和Symfony2将unicode数据插入Oracle数据库

时间:2012-11-13 11:02:29

标签: php oracle symfony unicode doctrine-orm

我正在使用Symfony2和Doctrine2编写应用程序,我需要使用Oracle作为我的数据库(我不熟悉它,我几乎总是使用MySQL)。我在开发箱上安装了Oracle XE并创建了一个用户。

我的连接参数在我的Symfony2配置中如下所示:

database_driver: oci8
database_host: localhost
database_name: xe
database_user: myusername
database_password: mypassword
database_port: 1521
database_charset: AL32UTF8

在CLI上运行php app/console doctrine:schema:create时,架构已成功创建,但在尝试使用php app/console doctrine:fixtures:load加载初始灯具时,我收到以下错误:

[Doctrine\DBAL\DBALException]
An exception occurred while executing 'INSERT INTO my_currency 
(id, code, name, symbol) VALUES (?, ?, ?, ?)' with params 
{"1":3,"2":"RUB","3":"Russian Ruble","4":"\u0440\u0443\u0431."}:

ORA-12899: value too large for column "MYUSERNAME"."MY_CURRENCY"."SYMBOL" 
(actual: 7, maximum: 4)

我的灯具脚本中包含以下数据,用于插入此行:

array('RUB', 'Russian Ruble', 'руб.'),

该实体定义为:

Foo\MyBundle\Entity\Currency:
  type: entity
  table: my_currency
  id:
    id:
      type: integer
      generator: { strategy: AUTO }
  fields:
    code:
      type: string
      length: 3
    name:
      type: string
      length: 64
    symbol:
      type: string
      length: 4

据我所知,Oracle XE的默认字符集为UTF-8,因此字段类型不需要设置为NVARCHAR2(它们由Doctrine自动设置为VARCHAR2)。

有没有人对我出错的地方有任何想法?

2 个答案:

答案 0 :(得分:3)

您的问题不是来自PHP:您的"MY_CURRENCY"."SYMBOL"列可能定义为VARCHAR2(4 byte)而不是VARCHAR2(4 CHAR)

由于unicode字符可能需要多个字节,因此在定义表变量时必须使用CHAR。这就是您收到Oracle错误的原因。

您应该可以修改表格:

ALTER TABLE MY_CURRENCY MODIFY (SYMBOL VARCHAR2(4 CHAR));

然后在此列中插入任意4个字符。

答案 1 :(得分:2)

首先,您使用的是哪个版本的Oracle XE以及您使用的字符集是什么?如果您使用的是10g版本的Oracle XE,除了使用Unicode字符集的版本之外,还可以选择下载使用西欧字符集的版本。这些查询会返回什么?

SELECT *
  FROM v$version

SELECT *
  FROM v$nls_parameters
 WHERE parameter LIKE '%CHARACTERSET';

假设数据库使用的是Unicode字符集,默认情况下,Oracle以字节而不是字符的形式指定VARCHAR2列(或NVARCHAR2列)的长度。如果您的数据超出US7ASCII字符集,则AL32UTF8字符集需要超过1个字节的存储空间。您尝试插入SYMBOL列的数据似乎需要7个字节的存储空间,尽管它可能只包含4个字符。

处理此问题有两种常用方法。第一种方法是将您分配的列的大小增加三倍(AL32UTF8字符集中的单个字符通常不需要超过三个字节,但某些例外情况需要四个字节)。您可以指定12个字节的长度(CODE将变为9个字节而NAME变为192个字节),而不是指定4个字节的长度。第二个是更改NLS_LENGTH_SEMANTICS,以便VARCHAR2列分配字符大小而不是字节

ALTER SYSTEM SET nls_length_semantics = CHAR scope= BOTH

一旦这样做(您需要以SYS身份登录才能更改初始化参数),框架生成的任何脚本都将默认使用字符语义。