我正在使用Symfony2和Doctrine2编写一个应用程序,其中我需要使用Oracle作为我的数据库(我不熟悉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
加载我的初始fixture时,我得到以下错误:
[DoctrineDBALDBALException]
An exception occurred while executing 'INSERT INTO my_currency
(id, code, name, symbol) VALUES (?, ?, ?, ?)' with params
{"1":3,"2":"RUB","3":"Russian Ruble","4":"u0440u0443u0431."}:
ORA-12899: value too large for column "MYUSERNAME"."MY_CURRENCY"."SYMBOL"
(actual: 7, maximum: 4)
我的fixtures脚本中有以下数据用于插入此行:
array('RUB', 'Russian Ruble', 'руб.'),
实体定义为:
FooMyBundleEntityCurrency:
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
据我所知,OracleXE的默认字符集为UTF-8,因此字段类型不需要设置为NVARCHAR2(它们由Doctrine自动设置为VARCHAR2)。
有人知道我哪里错了吗?
您的问题不是来自PHP:您的"MY_CURRENCY"."SYMBOL"
列可能被定义为VARCHAR2(4 byte)
而不是VARCHAR2(4 CHAR)
。
由于unicode字符可能占用多个字节,因此在定义表和变量时必须使用CHAR
。这就是您收到Oracle错误的原因。
您应该能够修改您的表:
ALTER TABLE MY_CURRENCY MODIFY (SYMBOL VARCHAR2(4 CHAR));
然后在此列中插入任意4个字符。
首先,您使用的是哪个版本的Oracle XE以及使用的是什么字符集?如果您使用的是10g版本的Oracle XE,除了使用Unicode字符集的版本外,还可以选择下载使用西欧字符集的一个版本。这些查询返回什么?
SELECT *
FROM v$version
SELECT *
FROM v$nls_parameters
WHERE parameter LIKE '%CHARACTERSET';
假设数据库使用Unicode字符集,默认情况下,Oracle以字节而非字符的形式指定VARCHAR2
列(或NVARCHAR2
列)的长度。如果数据在US7ASICI字符集之外,则AL32UTF8字符集需要超过1个字节的存储空间。您试图插入SYMBOL
列的数据似乎需要7个字节的存储空间,尽管它可能只包含4个字符。
处理这一问题有两种通用方法。第一种是将分配的列的大小增加三倍(AL32UTF8字符集中的单个字符通常不需要超过三个字节,但在某些特殊情况下需要四个字节)。不指定4字节的长度,而是指定12字节的长度(CODE
变为9字节,NAME
变为192字节)。第二种是更改NLS_LENGTH_SEMANTICS
,以便VARCHAR2
列以字符而非字节分配大小
ALTER SYSTEM SET nls_length_semantics = CHAR scope= BOTH
一旦您这样做(您需要以SYS身份登录才能更改初始化参数),框架生成的任何脚本都将默认使用字符语义。