主に自分用メモ。例えば以下のようなコードからDBIハンドルを取得してるとする

use strict;
use DBI;

sub get_dbh {
DBI->connect_cached(....);
}

sub foo {
my $dbh = get_dbh();
$dbh->do(...);
}

sub bar {
my $dbh = get_dbh();
$dbh->do(...);
}

foo();
bar();
.... 
で、まぁSET NAMES utf8を自動的に発行したいなーと思ったので、get_dbhに手を入れる

sub get_dbh {
my $dbh = DBI->connect_cached(...);
$dbh->do("SET NAMES 'utf8'");
return $dbh;
}
そうするとget_dbh()内で DBIハンドル自体はconnect_cached()でキャッシュされた同じハンドルが返ってくるのだが、毎回SET NAMES 'utf8'が発行される。これは無駄だし、例えば一つ手前のステートメントの状態を期待するコードを書くと破綻する:

{
my $dbh = get_dbh();
$dbh->do("INSERT INTO ...");
}

{
my $dbh = get_dbh();
# get_dbh()にSET NAMES utf8がなければ、直前のステートメントはINSERT INTO
# get_dbh()にSET NAMES utf8があると、直前のステートメントは SET NAMES utf8
my $id = $dbh->{mysql_insertid}; # SET NAMES utf8の後なので、insertidは存在しない
}

なので、一回SET NAMES 'utf8'を発行したら、それを覚えていたい。だがDBIハンドルはハッシュのように扱えるものの、適当なキーを入れようとすると怒られる:
if (! $dbh->{MySuperSpecialFlag}) { # ERRRRRRORRRRRR
$dbh->{MySuperSpecialFlag} = 1; # ERRRRRRORRRRRR
$dbh->do("SET NAMES 'utf8'");
ところがprivate_で始まるキーなら使える!これで勝つる!
sub get_dbh {
my $dbh = DBI->connect_cached(...);
if (! $dbh->{private_my_super_special_flag}) {
$dbh->{private_my_super_special_flag} = 1;
$dbh->do("SET NAMES 'utf8'");
}
return $dbh;

ということで万事解決。
本件はちらっとつぶやいたら生き字引の@tokuhiromが覚えてたので助かりました。