悬而未决 – perl 程序读取数据库乱码
某系统,正常运行在服务器A,现想搬到服务器B。所有已知的环境至少大版本号都一致,大部分环境版本完全一致。
问题出现:在B上查询本地数据库一个内容是中文的varchar字段,dbi报错,如下:
1 2 3 4 |
[user@localhost]$ perl test.pl SELECT id from TABLE where name= "测试内容" limit 10 DBD::mysql::st execute failed: Illegal mix of collations (gbk_chinese_ci,IMPLICIT) and (latin1_swedish_ci,COERCIBLE) for operation '=' at test.pl line 16. DBD::mysql::st fetchrow_array failed: fetch() without execute() at test.pl line 17. |
随后就围绕着这个报错开始尝试。
首先是看数据库的各种字符集的配置,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
mysql> SHOW VARIABLES LIKE 'character_set_%'; +--------------------------+----------------------------+ | Variable_name | Value | +--------------------------+----------------------------+ | character_set_client | gbk | | character_set_connection | gbk | | character_set_database | gbk | | character_set_filesystem | binary | | character_set_results | gbk | | character_set_server | gbk | | character_set_system | utf8 | | character_sets_dir | /xxx/xxx/xxx/ | +--------------------------+----------------------------+ 8 rows in set (0.00 sec) mysql> SHOW VARIABLES LIKE 'collation_%'; +----------------------+----------------+ | Variable_name | Value | +----------------------+----------------+ | collation_connection | gbk_chinese_ci | | collation_database | gbk_chinese_ci | | collation_server | gbk_chinese_ci | +----------------------+----------------+ 3 rows in set (0.00 sec) |
系统、程序文件、数据库的相关参数、数据表、字段都是gbk,问题依旧。
但是注意到报错中,应该是“=”右侧是“latin1_swedish_ci,COERCIBLE”,所以开始考虑问题不在mysql上。
随后继续测试,在程序里直接查询问题出现的那个字段,得到的结果依旧乱码。但各种操作、直接在数据库里进行,都是正常的,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
[user@localhost]$ perl test.pl select name from TABLE limit 100 ?????? ?????? ?????? ?????? ?????? ?????? ?????? ?????? ?????? ?????? ?????? ?????? ?????? ?????? |
但是在程序里增加了set names gbk,查询结果就正常,如下:
1 2 |
my $conn = DBI->connect("DBI:mysql:db:localhost",$DBUSER,$DBPWD); $conn->do("set names gbk"); |
但是现有系统古老且平稳,上述的数据库连接到处存在,每处都增加set names gbk并不现实,故继续排查。
此时注意到mysql的配置文件中已有的一句话:init_connect
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
[user@localhost]# vim /etc/my.cnf [client] default-character-set = gbk [mysql] default-character-set = gbk [mysqld] datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock user=mysql # Disabling symbolic-links is recommended to prevent assorted security risks symbolic-links=0 character_set_server = gbk default-character-set = gbk init_connect = "set names gbk" |
顺手查了一下init_connect的作用,疑惑为什么不起作用。随后在这篇文章中,看到了一些其他的配置,添加到配置文件中测试:
1 2 3 4 |
collation-server = gbk_chinese_ci init_connect = "SET NAMES gbk" init_connect = 'SET collation_connection = gbk_chinese_ci' skip-character-set-client-handshake |
至此,问题解决。
另外,“skip-character-set-client-handshake”,这一句话还没有添加的时候,问题依旧,加上这一句之后,问题解决。于是又顺手查了一下这句话的作用,这里。
问题虽然解决,但在B服务器上为何出现这个问题现在并不知道,待查。
另,记录一篇文章。