数据库字符集引发的血案

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

      什么叫字符集:

      或许字符集这个概念不清楚,可是大家一定知道ASCII,他就是一个字符集。还有就是UTF-8等,由于计算机要处理不同的语言,有人开发纯英文,可是咱们中国人开发还是会出现中文的,计算机要处理不同的文字,所以也就有了非常多的字符集。这样计算机依据咱们的设置,来特定处理某些文字,可是假设字符集和你写的驴唇不正确马嘴。那么抱歉,乱码就出来了。所以我们变成的时候才回出现乱码。

说了这么多。咱们改咱们解决呢。

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

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

      查询字符集

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

      然后查看咱们的字符集,假设和server不一致要设置成一致。影响Oracle数据库字符集最重要的參数是NLS_LANG參数。

 它的格式例如以下: NLS_LANG = language_territory.charset

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

     当中:

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

     Territory: 指定server的日期和数字格式。

     Charset:  指定字符集。

     如:AMERICAN _ AMERICA. ZHS16GBK

     改动字符集
     在SQL*PLUS 中。以DBA登录

     conn username 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。这样才让两个程序的程序集一样。

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

       思考

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

       那么我们首先想到的就应该是中间计算机的编译没有正确的运行,既然一条语句在数据库中能运行。在程序中就不行,那么就是中间的字符集的这个过程了,由于程序就是依据字符集来编译的。所以我们首先想到的就是数据库中的字符集的设置,可是假设设置了不行怎么办,既然改动了数据库不可以。那就仅仅能改动程序了,所以接下来就是利用传參。然后一方面可以设置传參的字符集类型,一方面还能防止SQL语句的注入。

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

 


 

 

      

posted @ 2017-04-10 08:11  mfmdaoyou  阅读(143)  评论(0)    收藏  举报