現象としては、セッションIDは保存されているのに、セッションデータ(a_session)だけが保存されないという状況です。どうやらTEXT型のフィールドにStorableモジュールでnfreezeしたデータを入れることができないみたいなので、原因を調べてみました。。
MySQL リファレンスマニュアル :: 2.5.1 バージョン 4.0 から 4.1 へのアップグレードによると、
>
すべてのテーブルと文字列カラムがキャラクタセットを持つようになった。 See 章 9. 各国キャラクタセットと Unicode。 キャラクタセット情報は、SHOW CREATE TABLE と mysqldump によって表示される (MySQL バージョン 4.0.6 以降は、新しいダンプファイルを読み取ることはできる。これより前のバージョンは、新しいダンプファイルを読み取ることはできない)。<
ということで、4.1からはTEXT型がキャラクタセットを持つようになったようです。試しにshow create talbe sessionsを実行すると以下のように、CHARSET=ujisがついていました。
>
<
CREATE TABLE `sessions` (
`id` varchar(32) NOT NULL default '',
`a_session` mediumtext,
`timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=ujis
このことから、ujis(EUC)のキャラクタセットをもつTEXTフィールドにnfreezeしたujis以外の文字コードを含んだデータをインサートしようとしたため、データが空になってしまうのではと予想しました。
そこでSledge::Session::Pgにならって、nfreezeしたものをbase64エンコードして、ujisの文字コード内で表現できるデータにしてからインサートするようにしたところ、うまくデータを保存できるようになりました。実際には以下のようなSledge::Session::MySQLのサブクラスを作って、替わりにcreate_sessionにセットしてあげました。
>
<
package Sledge::Session::MySQL41;
use strict;
use base qw(Sledge::Session::MySQL);
use MIME::Base64;
sub _serialize {
my($self, $data) = @_;
return encode_base64(Storable::freeze($data));
}
sub _deserialize {
my($self, $data) = @_;
return Storable::thaw(decode_base64($data));
}
1;
ボクは、textじゃなくて、longblobを使うようにしてました。
返信削除MLに投げようとおもって忘れてた。
きむらさんこんにちは。
返信削除なるほど、セッションデータ自体がバイナリであること考えると、型をlongblob型などに変える方が自然ですね。
あいらも同じはまりをして base64で逃げましたw。
返信削除my.cnfでdefault-charsetを binary にっていう人もいましたけど。。。
(変換しないという意味で)
binaryにっていうのはちょっと強引な気もしますね。
返信削除やはり、きむらさんのa_sessionの型をblogにするというのが、お手軽だし、まっとうな方法ですかねー。