MYSQL数据库的编码是相当灵活,可以随意定义到数据库的默认编码,表的默认编码,字段的编码。
但从数据的本质来讲,无论任何编码都是一堆字节数据。那mysql是根据什么配置来确定我们数据的编码,帮我们正确去储存数据。特别是对于多字节编码的数据,中文,韩文,日文。当然可以采用utf-8,或ucs2来适应这些编码,而且工作量也大为减少。但实际情况中有可能用到本地编码来定义数据表、字段编码,例如我们的实际输入的数据编码是gbk,但数据库或表或字段是utf-8,,而我们又没执行set names 编码名来确定我们数据的编码,mysql去采用默认的default-character-set来决定是否要转码再储存。又或者我们程序中转码再执行sql储存数据。而这一切都是为了保证我们储存到数据库编码的正确。所以set names 编码名和视图编码、视图输入数据的编码一致的时候我们程序就不会显示乱码。从mysql手册中查得SET NAMES 'charset_name' 和 SET CHARACTER SET charset_name是类似的。他们的区别如下:
SET character_set_client = charset_name;
SET character_set_results = charset_name;
SET character_set_connection = charset_name;
SET CHARACTER SET charset_name 等价
SET character_set_client = charset_name;
SET character_set_results = charset_name;
SET collation_connection = @@collation_database;
由上可见,两者作用是类似的,只是第二个命令多了collation_connection 为连接校对字符集。
对于这两个命令,我们可以简单的理解:
前些天在tp群中,有群友提出了特定编码的php源文件中,定义的sql数据保存到数据库中数据后的编码问题,以及乱码的产生原因。于是做了以下一个简单的实验。
-----------------------------------------------------------------------------------------------------------------
测试表结构
CREATE TABLE `hello` ( `id` int(32) NOT NULL AUTO_INCREMENT, `username` varchar(32) CHARACTER SET gbk NOT NULL, `password` varchar(32) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8
-----------------------------------------------------------------------------------------------------------------
测试写入数据,定义在源文件中:
$conn = mysqli_connect('localhost','root','mydb','pss_demo'); //由实际测试决定是否执行该行 /*mysqli_query($conn,'set names gbk;');*/ mysqli_query($conn,"insert into hello values(null,'你妹','12345678');"); mysqli_commit($conn );
-----------------------------------------------------------------------------------------------------------------
测试结果:
默认客户端编码 | 数据表编码 | 字段编码 | 源文件编码 | 是否乱码 | 是否set names 编码 |
utf8 | utf8 | gbk | gbk | 乱码 | 否 |
utf8 | utf8 | gbk | gbk | 乱码 | 是(utf8) |
utf8 | utf8 | gbk | gbk | 正常 | 是(gbk) |
utf8 | utf8 | gbk | utf8 | 正常 | 否 |
utf8 | utf8 | gbk | utf8 | 正常 | 是(utf8) |
utf8 | utf8 | gbk | utf8 | 乱码 | 是(gbk) |
结论:对于定义在源文件的中文数据是按源文件的编码来储存的,发送给mysql服务器时候是直接发送定义好的数据,编码未曾改变。假如没有set names 编码,会采用mysql默认的default-character-set来进行编码的检查转换。假如发送的数据和mysql设置的默认default-character-set不一致,mysql又执行从default-character-set到实际的字段的编码转换,所储存的数据就会是乱码。转码始终存在,比如说,你发出的sql语句包含的中文是gbk编码的,而你没set names,假如mysql的默认default client charset 是utf8,那么mysql就会把你发出gbk数据当做utf8来进行处理。所储存到的字段又是gbk的话,mysql会将你的gbk数据当是utf8,执行从utf8转码到gbk,再储存所以乱码就产生了。