mysql字符集含義請看mysql手冊第10.1節Character Set Support
mysql的字符集轉換過程請看鳥哥博客的這一篇
0. 初始狀態
debian使用apt安裝的mysql一開始是這樣的
可以看到默認情況下
sever的字符集是latin1
db的字符集是latin1
mysql cli的client和connect的字符集是utf8
(pdo連接的client和connect的默認字符集是latin1)
1. server charset
server的字符集設置可以通過配置文件修改
vim /etc/mysql/my.cnf
在[mysqld]部分添加
character_set_server = utf8
重啟mysql
可以看到server的默認字符集變成了utf8
2. db charset
設置server字符集后,數據庫的默認字符集也變成了和server相同的utf8
此外,在修改server字符集的情況下,還可以通過創建數據庫時指定字符集的方式設置數據庫字符集
如下圖,server和database的默認字符集都是latin1
創建數據庫test
create database test character set utf8;
此時默認的server和db字符集仍是latin1
但是此時數據庫test的默認字符集已經被修改為utf8
3.table charset
設置了數據庫的字符集,表的字符集若未設置則使用數據庫的字符集
此外,還可以在創建表時指定表的字符集CREATE TABLE `user` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(64) NOT NULL DEFAULT '', `email` varchar(64) NOT NULL DEFAULT '', `age` tinyint(3) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
4. column charset
設置了表的字符集,表列的字符集默認使用表的字符集
此外,還可以在創建表時指定列的字符集
CREATE TABLE `user2` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(64) CHARACTER SET latin1 NOT NULL DEFAULT '', `email` varchar(64) CHARACTER SET latin1 NOT NULL DEFAULT '', `age` tinyint(3) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;下圖可見,表字符集為utf8,列字符集為latin1

5.conect charset
客戶端和連接的字符集需要在客戶端設置,否則默認為latin1
$dsn = 'mysql:host=127.0.0.1;dbname=test'; $user = 'root'; $password = 'root'; $pdo = new PDO($dsn, $user, $password); $name = $_GET['name']; $email = $_GET['email']; $age = $_GET['age']; $sql = 'insert into user (name,email,age) values (:name,:email,:age)'; $stmt = $pdo->prepare($sql); $stmt->bindParam(':name', $name, PDO::PARAM_STR); $stmt->bindParam(':email', $email, PDO::PARAM_STR); $stmt->bindParam(':age', $age, PDO::PARAM_INT); $stmt->execute();
通過訪問
http://www.test.com/?name=你好&email=123@test.com&age=20
執行上述代碼,在mysql cli的字符集為utf8時name顯示亂碼,
客戶端在連接到mysql后,執行
set names utf8;
php代碼中表示為
5.1
$pdo = new PDO($dsn, $user, $password); $pdo->exec('set names utf8');
再次訪問url,可見連接字符集已設置為utf8
此外,還可以通過pdo連接時設置字符集
5.2
$dsn = 'mysql:host=127.0.0.1;dbname=test;charset=utf8'; $user = 'root'; $password = 'root'; $pdo = new PDO($dsn, $user, $password);
以及這樣
5.3
$attr = array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES UTF8'); $pdo = new PDO($dsn, $user, $password, $attr);

參考資料
msyql手冊 http://dev.mysql.com/doc/refman/5.5/en/charset.html
laruence博客 http://www.laruence.com/2008/01/05/12.html
stackoverflow http://stackoverflow.com/questions/4361459/php-pdo-charset-set-names
http://stackoverflow.com/questions/18496557/pdo-utf-8-encoding-issue