| 場景 | 問題 | 解決方案 |
|---|---|---|
| MySQL 字符集 UTF8 | 讀取中文亂碼 | 啟用 use utf8; + 三標準流 binmode |
| 用戶輸入含單引號/反斜槓 | SQL 拼接報錯/注入 | 佔位符 ? + execute(@params) + qq// 包裹字符串 |
| 長連接閒置超時 | MySQL server has gone away | mysql_auto_reconnect=1 或會話級調大 wait_timeout |
use utf8;
binmode(STDOUT, ':encoding(utf8)');
binmode(STDIN, ':encoding(utf8)');
binmode(STDERR, ':encoding(utf8)');
my $dbh = DBI->connect("dbi:mysql:dbname=test;host=localhost;mysql_enable_utf8=1",
'user', 'pass', { RaiseError => 1, PrintError => 0 });
mysql_enable_utf8=1(DBD::mysql 4.004+)自動設置連接字符集為 utf8mb4。binmode 確保標準流編碼一致,避免終端顯示亂碼。# ❌ 危險:字符串拼接
$dbh->do("INSERT INTO t(c) VALUES('$user_input')");
# ✅ 安全:佔位符 + execute 參數綁定
my $sth = $dbh->prepare("INSERT INTO t(c) VALUES(?)");
$sth->execute($user_input);
# 批量插入示例
my $sth = $dbh->prepare("INSERT INTO week_event VALUES(?,?,?,?,?,?,?)");
$sth->execute($OId, $CId, $Time, $EventType, $CDesc, $PId, $RFlag);
# 若字符串變量可能含特殊字符,用 qq// 確保作為標量傳遞
$sth->execute($OId, $CId, qq/$Time/, $EventType, qq/$CDesc/, $PId, $RFlag);
$dbh->{mysql_auto_reconnect} = 1;
# 連接斷開時,下次方法調用自動重連並重試
$dbh->do("SET SESSION wait_timeout=72000");
$dbh->do("SET SESSION interactive_timeout=72000");
# 20 小時無操作不斷開,適用於長跑批處理腳本
原理:MySQL 默認 wait_timeout=28800(8 小時),長連接閒置超過此值被 Server 主動斷開,客戶端再發包即報 gone away。
#!/usr/bin/perl
use strict; use warnings;
use DBI; use utf8;
binmode(STDOUT, ':encoding(utf8)');
binmode(STDERR, ':encoding(utf8)');
my $dbh = DBI->connect("dbi:mysql:dbname=prod;host=10.0.0.1;mysql_enable_utf8=1",
'app', 'secret', { RaiseError => 1, AutoCommit => 0 });
$dbh->{mysql_auto_reconnect} = 1;
my $sth = $dbh->prepare("INSERT INTO events(uid,type,msg,ts) VALUES(?,?,?,?)");
open my $fh, '<:encoding(utf8)', 'events.csv' or die $!;
while (<$fh>) {
chomp; my @f = split /,/;
$sth->execute(@f);
$dbh->commit if $. % 1000 == 0;
}
$dbh->commit;
$dbh->disconnect;
避坑總結:佔位符防注入、utf8mb4 防亂碼、auto_reconnect 防斷連——三板斧打通 Perl 操作 MySQL 的任督二脈。