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 NAMES '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 为连接校对字符集。
对于这两个命令,我们可以简单的理解:
character_set_client告诉mysql:我们的程序向你发送的数据是什么字符集编码的,如果和要存储的字段的编码不一样,你要帮我转码再储存。
character_set_results告诉mysql:我的程序需要显示的数据是什么字符集编码的,如果你储存在库中的编码和我要的编码不一样,你要为我转码再返回给我。
SET character_set_connection告诉mysql:我连接你mysql的连接过程中使用的是什么字符集编码,你不要搞混了。
SET collation_connection告诉mysql:我的数据校对采用什么字符集编码,你排序、索引的时候要按这个来搞。
前些天在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,再储存所以乱码就产生了。