當 LOAD DATA INFILE 不可用(權限受限、版本限制、遠程導入)時,通用 Shell + MySQL 客戶端腳本可實現 CSV 穩健導入,關鍵在於字符集一致性與幂等寫入。
employee.csv(UTF-8 編碼,列:ds, id, name)wechat_employee(ds VARCHAR(20), femployeeid INT, femployeename VARCHAR(256)) ENGINE=InnoDB DEFAULT CHARSET=utf8LOAD DATA LOCAL INFILE 或受 secure_file_priv 限制)-- 1. 服務端字符集 SHOW VARIABLES LIKE 'character_set_%'; -- 期望:client/connection/database/results/server 均為 utf8/utf8mb4 -- 2. 表字符集 SHOW CREATE TABLE wechat_employee; -- 期望:DEFAULT CHARSET=utf8 (或 utf8mb4) -- 3. 客戶端連接字符集(導入前設置) SET NAMES utf8; -- 或 utf8mb4 -- 等價於: SET character_set_client = utf8; SET character_set_connection = utf8; SET character_set_results = utf8;
原則:文件編碼 = 客戶端連接編碼 = 表存儲編碼,任一不一致導致亂碼。
#!/bin/bash
# import_employee.sh
# 用法:chmod +x import_employee.sh && ./import_employee.sh
CSV_FILE="./employee.csv"
DB_USER="root"
DB_PASS="655453"
DB_NAME="test"
TABLE="wechat_employee"
# 逐行讀取 CSV(假設無標題行,無引號包裹,純逗號分隔)
while IFS=',' read -r ds id name; do
# 跳過空行
[[ -z "$ds" ]] && continue
# 顯式指定字符集執行 REPLACE INTO(主鍵/唯一鍵衝突時覆蓋)
mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" \
--default-character-set=utf8 \
-e "REPLACE INTO \`$TABLE\` (\`ds\`, \`femployeeid\`, \`femployeename\`) VALUES ('$ds', '$id', '$name');"
# 進度提示
echo "Imported: ds=$ds, id=$id, name=$name"
done < "$CSV_FILE"
echo "Import completed."
| 點 | 說明 |
|---|---|
IFS=',' | 設置輸入字段分隔符為逗號,配合 read -r 保留反斜線。 |
REPLACE INTO | 主鍵/唯一鍵衝突時 DELETE + INSERT,實現幂等導入(可重跑)。 |
--default-character-set=utf8 | 強制客戶端連接字符集,覆蓋環境變量/配置文件設置。 |
| 單行提交 | 每行獨立事務,失敗不影響後續;大數據量(>1萬)建議批次 BEGIN; ... COMMIT;。 |
| 特殊字符轉義 | CSV 含單引號/反斜線時需預處理轉義,或改用 LOAD DATA / Python csv 模組 + 參數化。 |
#!/usr/bin/env python3
import csv, mysql.connector, sys
def import_csv(csv_path, db_config, table):
with open(csv_path, 'r', encoding='utf-8') as f:
reader = csv.DictReader(f) # 假設有標題行
conn = mysql.connector.connect(**db_config)
cursor = conn.cursor()
sql = f"REPLACE INTO `{table}` (`ds`, `femployeeid`, `femployeename`) VALUES (%s, %s, %s)"
batch = []
for row in reader:
batch.append((row['ds'], int(row['id']), row['name']))
if len(batch) >= 1000:
cursor.executemany(sql, batch)
conn.commit()
batch.clear()
if batch:
cursor.executemany(sql, batch)
conn.commit()
cursor.close()
conn.close()
if __name__ == '__main__':
config = {
'host': 'localhost', 'user': 'root', 'password': '655453',
'database': 'test', 'charset': 'utf8', 'use_unicode': True
}
import_csv('./employee.csv', config, 'wechat_employee')
file -i employee.csv 編碼、MySQL 連接字符集、表字符集三者一致。INSERT IGNORE(跳過)或 ON DUPLICATE KEY UPDATE(部分更新)。autocommit/unique_checks/foreign_key_checks、使用 LOAD DATA(若可用)。read 無法正確解析,必須用 Python csv 模組或專業 ETL 工具。