背景:
项目使用oracle数据,在开发环境测试一些正常。项目部署到客户的服务器上后,系统在添加数据的时候报错。输出错误信息,发现是“超出最大长度”的异常。
但是按照数据库的设计,添加的数据应该在允许的数据长度范围内。那么是什么原因导致的呢,因是客户自己按照的oracle数据库,怀疑是部署环境的oracle参数设置和开发环境的不同。
过程:
查询oracle的相关参数:select * from nls_database_parameters;开发数据库和部署数据的查询结果如下:
开发数据库:
部署数据库:
经比较,发现开发库和部署库的 nls_characterset参数的值是不同的。
那么一个汉字和一个英文字母在开发库和部署库中各自占几个字节呢? 我们可以用sql语句查询一下。
select lengthb('金') from dual;
select lengthb('a') from dual;
开发库 | 部署库 |
经查询一个汉字在开发库中占2个字节,而在部署库中占三个字节。
我们可以进一步看一下“金”这个汉字在开发库中和部署库中到底存储成了什么。
使用语句: select dump('金',1016) from dual;
开发库 | 部署库 |
可以看到汉字“金”在开发库中存储为 bd f0 占用2个字节,而在部署库中存储为 e9 87 91 占用3个字节。
结论:那么根据以上的信息,我们可以得出结论 当nls_characterset=zhs16gbk 时,一个汉字在oracle中占用2个字节,当nls_characterset=al32utf8时,
一个汉字在oracle中占用3个字节。
解决问题:
现在原因基本上已经找到了,那么如何解决。这也就到了我今天想要表达的主题“规避风险”。
网上一搜,发现遇到此问题的同学还是比较多的,下面给出了修改nls_characterset和nls_length_semantics参数的方法,都可以使问题得到解决。
但是修改参数可能带来的后果是非常严重的,风险系数比较高。是采用修改参数的方法是另辟蹊径。我选择了后者。
那么是否可以将数据库中的varchar2类型的字段长度扩充进而规避该问题,虽然该方法也有一定的弊端,可以在项目扩充上会有遗留问题,但是在目前来看不失为一个低风险的好方法。
生成扩充脚本的sql语句如下 :
select 'alter table '||table_name||' modify '||column_name||' VARCHAR2('||data_length*2||');'
from cols
where data_type = 'VARCHAR2'
and table_name in (select table_name from tabs where status = 'VALID')
生成数据脚本如下:
参数资料: