Asynchronous MySQL Queries in Perl Using DBD::mysql and AnyEvent
A lot of people use MySQL, and these days, asynchronous-style programming has really taken off. If you're involved in both of these camps, you may be wondering
how to send a query to MySQL and have it inform your event loop when it's ready with the results of that query. A common solution is to use a thread or child process
for each connection, and exchange data using IPC. However, if you're using Perl and DBD-mysql 4.019 or better, you have an alternative: the new asynchronous interface.
Using the new async flag that you can provide to the prepare method, along with the new mysql_fd method, it's fairly easy to have MySQL play nice with AnyEvent.
Here's a simple example:
#!/usr/bin/env perluse strict;
use warnings;
use feature 'say';use AnyEvent;
use DBI;my $dbh = DBI->connect('dbi:mysql:', undef, undef, {
PrintError => 0,
RaiseError => 1,
});my $cond = AnyEvent->condvar;
my $sth = $dbh->prepare('SELECT SLEEP(10), 3', { async => 1 });
$sth->execute;my $timer = AnyEvent->timer(
interval => 1,
cb => sub {
say 'timer fired!';
},
);my $mysql_watcher = AnyEvent->io(
fh => $dbh->mysql_fd,
poll => 'r',
cb => sub {
say 'got data from MySQL';
say join(' ', $sth->fetchrow_array);
$cond->send;
},
);$cond->recv;
undef $sth;
$dbh->disconnect;
This script will print "timer fired!" about once a seconds for ten seconds, then "got data from MySQL", and finally "0 3", which is the data from our SELECT statement. Obviously, this example is pretty trivial, but you could easily do this with multiple MySQL connections.
(cross-posted from my blog)
That makes it easy to play with just about any eventy system, including POE, Reflex, and IO::Async. In fact, here's your sample program ported to Reflex: https://github.com/rcaputo/reflex/blob/master/eg/eg-20-mysql.pl
> cpanm DBD::mysql
DBD::mysql is up to date. (4.020)
still get DBD::mysql::db prepare failed: Async support was not built into this version of DBD::mysql at async_mysql.pl line 17.
working on Strawberry Perl on Windows
Ah, sorry! I forgot to mention that asynchronous support is not yet working on Windows; the internals rely on select() for one or two of the special method calls. Patches are, of course, welcome. =)
I wanted to make sure anyone could make use of it; not everyone likes/prefers AnyEvent, after all!
Sadly it seems that asynch support doesn't only not work on windows, it seems to have actively broken any and all error handling, making DBD::mysql act more like PHP than anything else. (Then again, MySQL is the PHP among databases.)
Please do take a look here: http://bugs.activestate.com/show_bug.cgi?id=91426
This is very cool!
@Mithaldu
just can confirm this bug after installing the new version, going back to 4.016
Ouch...sorry about that. I'll see if I can do something to fix it, but unfortunately I don't have a Windows machine to test on.
Email me at walde.christian@googlemail.com and i'll send you login data for a VNC server on a Win7 machine. :)