技术开发 频道

MySQL应用开发中遇到的几个问题与解决方法

  【IT168技术文档】我们单位是个综合性的门诊部,目前联网工作的机器有近二十台,门诊日常工作的关键流程基本上都在网上进行。我们目前的数据库软件使用的就是MySQL,下面把我在使用MySQL中遇到的一些问题与大家交流。

  一、从ORACLE到MySQL

  最初设计的单位信息系统,工作平台时使用的是Windows环境,工作站跑98,服务器跑2000,因为对MySQL并不熟悉,所以数据库选用的是ORACLE。

  三年前开始准备向linux开发环境过渡,正好当时单位有许多新业务要向局域网上移植,网络上的业务量大大增加,老服务器速度太慢,于是新购置一台服务器,联想T280,装机的时候我就直接装上了红旗linux的操作系统,数据库就使用了系统里带的MySQL。

  在Windows环境中我的开发工具是C++Builder,数据库接口用的是开发工具里带的BDE。使用ORACLE时,BDE里直接有ORACLE的驱动,使用MySQL时稍稍麻烦一点,BDE里没有直接对MySQL的驱动,但可以通过ODBC的方式和MySQL连接。首先安装MySQL官方的ODBC驱动程序,然后在控制面板的数据源里添加系统DSN,把MySQL服务器加进去,添加成功之后,在BDE里就会看到刚才添加的DSN,程序访问MySQL就通过这个DSN来完成。

  之后就是程序的修改。从ORACLE转向MySQL的程序移植比较突出的问题有两个:一是数据表的名称大小写问题,二是函数问题。

  在送往ORACLE服务器的SQL语句中,数据表名的大小写是不敏感的,SQL语句大小写的区别仅仅是为了美观,但在Linux上的MySQL里,大写和小写的表名称含义却不一样,“TABLE”和“table”在ORACLE里表示的同一个表,但在MySQL里它们是两个不同的表。

  函数问题比较突出的一个是关于日期的函数。在程序里许多地方的操作都与日期有关,ORACLE中用到日期的SQL语句中一般都是这么写:to_date('2009-02-03','yyyy-mm-dd'),在MySQL中却可以直接这么写:‘2009-02-03’,取系统日期的函数在ORACLE中是sysdate,在MySQL中则是curdate()。其它的函数因为用的比较少,所以矛盾并不突出。

  把这两个问题解决之后,程序就可以正常运行了。当时的移植并没有一步到位,采用了逐步过渡的方法,有些数据表放在ORACLE里,有些数据表放在MySQL里,共用了一段时间后,才完全移植到MySQL上。

  二、从windows到linux

  去年下半年开始了从windows环境向linux环境移植。在linux下我的开发工具是Qt4,这次遇到的突出问题只有一个,内码。

  Qt的工作内码是Unicode.而MySQL默认的字符集是Latin1。当时初始建立MySQL服务环境时,建库,建表都使用的默认字符集,与Windows工作站的连接没有内码问题。现在转到linux环境下,内码问题如不解决,一切就无法向下进行。

  经过一段时间的摸索,找出了以下解决办法:

  1、在MySQL中不论是新建数据库还是新建数据表,都要加上参数 default character set utf8。这样建立的表就避免了日后应用时的麻烦。

  2、旧数据库移植

  第一步:数据导出

  mysqldump -h host -u user -ppasword --default-character-set=latin1 --skip-opt -B database --tables tablename > old.sql

  --skip-opt 参数不能缺少,如缺少则生成的脚本里insert语句太大,导入时可能会出现错误提示:

  ERROR 1153 (08S01) at line xxx: Got a packet bigger than 'max_allowed_packet' bytes

  加上这个参数,每条记录只对应一个insert语句,虽然导出的文件大一些,但防止了出错。

  第二步:转换备份文件的字符集

  iconv -f gbk -t utf8 -c old.sql > new.sql

  第三步:修改数据导出文件

  用纯文本编辑工具,(比如KWrite)打开new.sql,在开头部分找到 create DATABASE 句,把句尾注释掉的default character set 加上。然后替换文件中的所有的字串”latin1“为”utf8“,然后存盘。

  第四步:导入最终格式的数据

  mysql -h host -u user -p password < new.sql

  有一点要注意,以上操作必须在Linux的终端窗口下进行,在windows下通过telnet登录到linux服务器的窗口里操作,不会得到正确结果。

  3、在Qt中与默认字符集为latin1的MySQL连接:

  如果你的数据库因为种种原因不能转为utf8内码,那在Qt编程时可以这样处理。

  向MySQL送汉字:

  QTextCodec *tdc=QTextCodec::codecForName("GB2312");

  query.exec("insert into table (field) values('"+tdc->fromUnicode(QString::fromLocal8Bit("汉字"))+"')");

  从查询结果取汉字:

  QTextCodec *tcdc=QTextCodec::codecForName("UTF-8");

  id = tcdc->toUnicode (query.value(0).toByteArray() );

  4、设定Qt工作字符集:

  数据库内码全部转为utf8之后,Qt编程就大为方便,只需在main函数中加上下面这三句话:

  QTextCodec::setCodecForTr(QTextCodec::codecForName("utf-8"));

  QTextCodec::setCodecForLocale(QTextCodec::codecForName("utf-8"));

  QTextCodec::setCodecForCStrings(QTextCodec::codecForName("utf-8"));

  然后在连接MySQL时先发送一条指令:

  set names utf8

  之后在程序内部就不用考虑内码问题了。

  5、在windows终端下访问字符集为utf8的MySQL

  就象我目前的情况,linux模块还没全部完成,只能在部分节点上投入使用,其它大部分的节点上用的还是windows下的程序,这时windows与utf8内码该怎样相处呢?其实很简单,只需要在程序初始化之后,向MySQL服务器发送一条指令:

  set names gbk

  然后一切都不用改变。

  6、mysql中的汉字排序问题

  在当年使用Latin1内码时,这个问题我其实一直也没彻底解决。当时的折衷方案是,使用:

  order by convert(field using binary)

  这样虽然可以解决大部分的汉字问题,但有个别冷僻字排的顺序仍然不正确,比如我们单位的一些工作人员的姓,无法正确按字母表的顺序排出。

  使用utf8内码后,这个问题居然全部解决了:

  order by convert(field using gbk)

  这时从前不正确的汉字顺序,全部都能按字母表顺序排出。

  7、字段值字母大小写不敏感的解决

  使用utf8内码时,如果你比较两个字段的值,“Abc“和”abc“,那你得到的结果是这两个字段相等。虽然大多数情况下这没有问题,但如果你需要精确比较字串时这就是个麻烦事。这个问题可以这么解决:需要使用字段值时,使用 convert(field using latin1) collate latin1_general_cs,这时就可以选择出大小写敏感的字段值。

  比如 select name from sys_staff where convert(idabs using latin1) collate latin1_general_cs ='sdp';这样,就可以把你不想要的结果屏闭掉。

        MySQL做为一款轻便易用功能强大的数据库新产品,在中小企业中很有大力推广的必要。

 

0
相关文章