现在的位置: 主页 > 在线留言 > 文章列表

数据库字符集引发的血案

作者:潜江市宏光畜牧有限公司 来源:www.qjhgnm.com 未知发布时间:2017-09-11 14:15:35
数据库字符集引发的血案

以前开发的时候,大家用的都是SQL Server,.net开发,一直都用的没什么问题,但是最近开发用的Oracle,本来开发的好好的,方法写的也没什么问题,但是重新装了一次系统以后,就发现我的程序不能查询根据汉子查询,如果SQL语句中出现了汉子,那么查询的结果就为空,但是表里边命名有数据,后来发现原来是数据库字符集搞的鬼。不知道大家有没有遇到这个问题,网上查了许多资料,经过一个一个实践,发现了几个方法。

什么叫字符集:

也许字符集这个概念不清楚,但是大家一定知道ASCII,他就是一个字符集,还有就是UTF-8等,因为计算机要处理不同的语言,有人开发纯英文,但是咱们中国人开发还是会出现中文的,计算机要处理不同的文字,所以也就有了很多的字符集,这样计算机根据咱们的设置,来特定处理某些文字,但是如果字符集和你写的驴唇不对马嘴,那么抱歉,乱码就出来了,所以我们变成的时候才回出现乱码。说了这么多,咱们改咱们解决呢。

方法一、设置数据库字符集。

如果出现了大家查询语句中有汉子的话,但是返回的结果是一个Null,那么大家首先就可以考虑一下是不是咱们的数据库的字符集设置有问题,所以咱们先尝试的改一下。

查询字符集

打开SQLPlus
SQL> select * from v$nls_parameters;

然后查看咱们的字符集,如果和服务器不一致要设置成一致。影响Oracle数据库字符集最重要的参数是NLS_LANG参数。 它的格式如下: NLS_LANG = language_territory.charset

它有三个组成部分(语言、地域和字符集),每个成分控制了NLS子集的特性。

其中:

Language: 指定服务器消息的语言, 影响提示信息是中文还是英文

Territory: 指定服务器的日期和数字格式,

Charset: 指定字符集。

如:AMERICAN _ AMERICA. ZHS16GBK

修改字符集
在SQL*PLUS 中,以DBA登录

conn 用户名 as sysdba

然后执行以下命令

>shutdown immediate; (把database停了)

>startup mount; (把database重开去可更改情況)

>alter system enable restricted session;

>alter system set job_queue_processes=0;

>alter system set aq_tm_processes=0;

>alter database open;

>alter database character set utf8;

OR

>alter database character set internal_use utf8;

>shutdown immediate;

>startup; (重开正常oracle)

从NLS_LANG的组成我们可以看出,真正影响数据库字符集的其实是第三部分。

所以两个数据库之间的字符集只要第三部分一样就可以相互导入导出数据,前面影响的只是提示信息是中文还是英文。当然我们在数据库中改,在环境变量里边也要改,右击我的电脑--》高级设置--》环境变量--》新建--》NLS_LANG=CHINESE_CHINA.ZHS16GBK .

当时这个方法好像在我这不给力,于是紧接着又找了一个方法

方法二、修改程序

因为我们是合作开发,我主要是负责界面,而另一个人为我提供接口,因为我不可能需要所有的数据,他返回的datatable的信息我是需要筛选的,所以我每次都是Dt.Select(xxxx='xxxx'),但是里边是汉字就是不可以。于是找了很多的方法,最后只能修改程序,开始我们的方式是直接写一条SQL语句,例如‘select t.sex from T_student where t.studentName = '张三',直接在数据库中查询没问题,但是在程序中就不行,后来我们发现也许是,NET的字符集和数据库的字符集不一样,这样是不是导致了解析出现的问题,后来就用了参数的方式,下边是我们的程序的代码,大家可以看一下。

StringBuilder sql2 = new StringBuilder(); sql2.Append( select c.s_keypartid from kpm_dict_i_scale c ); sql2.Append( where c.s_traintempid =:S_TRAINTEMPID ); sql2.Append( and c.s_repairlevel = :S_REPAIRLEVEL); OracleParameter[] parameters = { new OracleParameter(:S_TRAINTEMPID, OracleType.VarChar,20), new OracleParameter(:S_REPAIRLEVEL, OracleType.VarChar,20)}; parameters[0].Value = s_traintempid; parameters[1].Value = 转向架收支; DataTable dtpart = OracleHelper.ExecuteQuery(OracleHelper.ConnectionString, CommandType.Text, sql2.ToString(), parameters); if (dtpart != null && dtpart.Rows.Count > 0) { ***//数据转换 }


上边的程序是给我接口人的程序,但是这样调用以后,我发现就没有问题了,因为用了OracleParameter 的OracleType,这样才让两个程序的程序集一样。

后来在网上找了挺多资料的,也没有什么别的解决方式,所以只能修改程序。所以经过这次的经历,咱们以后开发,如果是自己开发,直接设置自己电脑的字符集就可以了,但是如果是合作开发,大家一定要提前注意,一定要和服务器的编码方式一样,这样才不会出现后期改代码的悲哀。

思考

当我开始发现这个问题的时候,还以为是自己的数据库出现了问题,后来发现数据库能查的出来,那就肯定不是数据库本身安装的问题,那么接下来就是我程序的问题,我的程序没有能正确的翻译SQL语句,以至于传到数据库中的时候SQL语句就变了,所以就是这个中间出现了问题。

那么我们首先想到的就应该是中间计算机的编译没有正确的执行,既然一条语句在数据库中能执行,在程序中就不行,那么就是中间的字符集的这个过程了,因为程序就是根据字符集来编译的。所以我们首先想到的就是数据库中的字符集的设置,但是如果设置了不行怎么办,既然修改了数据库不可以,那就只能修改程序了,所以接下来就是利用传参,然后一方面能够设置传参的字符集类型,一方面还能防止SQL语句的注入。

这个过程看起来简单,但是也废了我不少力气,希望能帮组到想我这样的程序猿们吧。

企业建站2800元起,携手武汉肥猫科技,做一个有见地的颜值派!更多优惠请戳:湖北网站建设 http://hubei.45qun.com

上一篇:TelephonyUtils 工具类 下一篇:最后一页