2017-02-21 105 views
2

Я занимаюсь модулем, который обеспечивает абстракцию над DBI, которая автоматически восстанавливается. Мне нужно выполнить некоторые действия после «DBI-> connect.Как подключиться после повторного подключения DBI

Есть ли способ добавить к нему крючок без изменения этого модуля? Мне не повезло найти его в документации. Я что-то пропустил?

+1

Я предполагаю, что вы прочитали раздел [обратные вызовы] (https://metacpan.org/pod/DBI#Callbacks) документации? Похоже, вы можете добавить обратный вызов к любому методу * кроме * connect! Все, что я могу придумать, - это запланировать обезьяну 'DBI :: connect', чтобы вызвать реальное' connect', а затем передать '$ dbh', который он возвращает. – Borodin

ответ

3

DBI doc имеет a chapter about subclassing, который упоминает метод $dbh->connected, который ничего не делает. Кажется, это именно то, что вы хотите.

Когда подклассы используются тогда, после успешной нового подключения, то DBI-> подключить метод автоматически вызывает:

$dbh->connected($dsn, $user, $pass, \%attr); 

Я не пробовал, но он может работать лишь на обезьяну - привязка этого подключенного метода к DBI напрямую без подклассификации. In connectthere is definitely a call to connected.

Но я не знаю, где его исправить. Возможно, в драйвере. Быстрый grep of the cpan показывает, что сюда относятся только два драйвера, включенные в DBI dist. DBD::Gofer и DBD::Proxy, но этот пуст. В обоих случаях он находится в пакете DBD::<drivername>::db.

Предположим, вы делаете MySQL, тогда вы пойдете и подключите его к своему драйверу. Либо подклассов и использовать этот драйвер, или просто обезьяна-латание его.

*DBD::mysql::db::connected = sub { 
    my ($dbh, dsn, $user, $pass, $attr, $old_driver) = @_; 

    warn 'Connected!'; 
} 

Это должно работать так же с другими водителями, если они не имеют свои собственные connected. В этом случае вы должны, вероятно, обернуть его вручную или использовать что-то вроде Class::Method::Modifiers's around, чтобы обернуть его, чтобы убедиться, что исходное поведение остается неповрежденным.

На данный момент у вас также есть подключенный $dbh, так что вы можете погулять в базе данных по адресу connected, если хотите.

Конечно, это даст вам обратный вызов после при каждом подключении. Если вы хотите получить только пересоединения, вы можете создать закрытие над лексической переменной, которая учитывает соединения и пропустит первый.

{ 
    my $connection_counter; 
    *DBD::mysql::db::connected = sub { 
     my ($dbh, dsn, $user, $pass, $attr, $old_driver) = @_; 

     return unless $connection_counter++; # skip first connection 
     warn 'Connected!'; 
    } 
} 

Обратите внимание, что я не тестировал это.

+1

Надеюсь, вы правы, но OP говорит: «Я имею дело с модулем, который обеспечивает абстракцию над DBI» *, который они не хотят изменять, поэтому использование подкласса не представляется возможным.Я думаю, что подклассы существующего подкласса могут работать, хотя, если это так, как абстракция выполняется. – Borodin

+0

И спасибо. Вы научили меня углу «DBI», о котором я не знал до сих пор. – Borodin

+0

@Borodin Я тоже не знал об этом. Мне посчастливилось скрасить документы. ;) – simbabque