.\" -*- mode: troff; coding: utf-8 -*- .\" Automatically generated by Pod::Man v6.0.2 (Pod::Simple 3.48) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>. .ie n \{\ . ds C` "" . ds C' "" 'br\} .el\{\ . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Required to disable full justification in groff 1.23.0. .if n .ds AD l .\" ======================================================================== .\" .IX Title "DBD::Multiplex 3" .TH DBD::Multiplex 3 2026-10-25 "perl v5.44.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH NAME DBD::Multiplex \- A multiplexing driver for the DBI. .SH SYNOPSIS .IX Header "SYNOPSIS" .Vb 1 \& use strict; \& \& use DBI; \& \& my ($dsn1, $dsn2, $dsn3, $dsn4, %attr); \& \& # Define four databases, in this case, four Postgres databases. \& \& $dsn1 = \*(Aqdbi:Pg:dbname=aaa;host=10.0.0.1;mx_id=db\-aaa\-1\*(Aq; \& $dsn2 = \*(Aqdbi:Pg:dbname=bbb;host=10.0.0.2;mx_id=db\-bbb\-2\*(Aq; \& $dsn3 = \*(Aqdbi:Pg:dbname=ccc;host=10.0.0.3;mx_id=db\-ccc\-3\*(Aq; \& $dsn4 = \*(Aqdbi:Pg:dbname=ddd;host=10.0.0.4;mx_id=db\-ddd\-4\*(Aq; \& \& # Define a callback error handler. \& \& sub MyErrorProcedure { \& my ($dsn, $mx_id, $error_number, $error_string, $h) = @_; \& open TFH, ">>/tmp/dbi_mx$mx_id.txt"; \& print TFH localtime().": $error_number\et$error_string\en"; \& close TFH; \& return 1; \& } \& \& # Define the pool of datasources. \& \& %attr = ( \& \*(Aqmx_dsns\*(Aq => [$dsn1, $dsn2, $dsn3, $dsn4], \& \*(Aqmx_master_id\*(Aq => \*(Aqdb\-aaa\-1\*(Aq, \& \*(Aqmx_connect_mode\*(Aq => \*(Aqignore_errors\*(Aq, \& \*(Aqmx_exit_mode\*(Aq => \*(Aqfirst_success\*(Aq, \& \*(Aqmx_error_proc\*(Aq => \e&MyErrorProcedure, \& ); \& \& # Connect to all four datasources. \& \& $dbh = DBI\->connect("dbi:Multiplex:", \*(Aqusername\*(Aq, \*(Aqpassword\*(Aq, \e%attr); \& \& # See the DBI module documentation for full details. .Ve .SH DESCRIPTION .IX Header "DESCRIPTION" DBD::Multiplex is a Perl module which works with the DBI allowing you to work with multiple datasources using a single DBI handle. .PP Basically, DBD::Multiplex database and statement handles are parents that contain multiple child handles, one for each datasource. Method calls on the parent handle trigger corresponding method calls on each of the children. .PP One use of this module is to mirror the contents of one datasource using a set of alternate datasources. For that scenario it can write to all datasources, but read from only from one datasource. .PP Alternatively, where a database already supports replication, DBD::Multiplex can be used to direct writes to the master and spread the selects across multiple slaves. .PP Another use for DBD::Multiplex is to simplify monitoring and management of a large number of databases, especially when combined with DBI::Shell. .SH COMPATIBILITY .IX Header "COMPATIBILITY" A goal of this module is to be compatible with DBD::Proxy / DBI::ProxyServer. Currently, the \*(Aqmx_error_proc\*(Aq feature generates errors regarding the storage of CODE references within the Storable module used by RPC::PlClient which in turn is used by DBD::Proxy. Yet it works. .SH "CONNECTING TO THE DATASOURCES" .IX Header "CONNECTING TO THE DATASOURCES" Multiple datasources are specified in the either the DSN parameter of the DBI\->\fBconnect()\fR function (separated by the \*(Aq|\*(Aq character), or in the \*(Aqmx_dsns\*(Aq key/value pair (as an array reference) of the \e%attr hash parameter. .SH "SPECIFIC ATTRIBUTES" .IX Header "SPECIFIC ATTRIBUTES" The following specific attributes can be set when connecting: .IP \fBmx_dsns\fR 4 .IX Item "mx_dsns" An array reference of DSN strings. .IP \fBmx_master_id\fR 4 .IX Item "mx_master_id" Specifies which mx_id will be used as the master server for a master/slave one\-way replication scheme. .IP \fBmx_connect_mode\fR 4 .IX Item "mx_connect_mode" Options available or under consideration: .Sp \&\fBreport_errors\fR .Sp A failed connection to any of the data sources will generate a DBI error. This is the default. .Sp \&\fBignore_errors\fR .Sp Failed connections are ignored, forgotten, and therefore, unused. .IP \fBmx_exit_mode\fR 4 .IX Item "mx_exit_mode" Options available or under consideration: .Sp \&\fBfirst_error\fR .Sp Execute the requested method against each child handle, stopping after the first error, and returning the all of the results. This is the default. .Sp \&\fBfirst_success\fR .Sp Execute the requested method against each child handle, stopping after the first successful result, and returning only the successful result. Most appropriate when reading from a set of mirrored datasources. .Sp \&\fBlast_result\fR .Sp Execute the requested method against each child handle, not stopping after any errors, and returning all of the results. .Sp \&\fBlast_result_most_common\fR .Sp Execute the requested method against each child handle, not stopping after the errors, and returning the most common result (e.g. three\-way\-voting etc). Not yet implemented. .IP \fBmx_shuffle\fR 4 .IX Item "mx_shuffle" Shuffles the list of child handles each time it\*(Aqs about to be used. Typically combined with an \f(CW\*(C`mx_exit_mode\*(C'\fR of \*(Aq\f(CW\*(C`first_success\*(C'\fR\*(Aq. .IP \fBmx_shuffle_connect\fR 4 .IX Item "mx_shuffle_connect" Like \f(CW\*(C`mx_shuffle\*(C'\fR above but only applies to \fBconnect()\fR. .IP \fBmx_error_proc\fR 4 .IX Item "mx_error_proc" A reference to a subroutine which will be executed whenever a DBI method generates an error when working with a specific datasource. It will be passed the DSN and \*(Aqmx_id\*(Aq of the datasource, and the \f(CW$DBI::err\fR and \f(CW$DBI::errstr\fR. .Sp Define your own subroutine and pass a reference to it. A simple subroutine that just prints the dsn, mx_id, and error details to STDERR can be selected by setting mx_error_proc to the string \*(AqDEFAULT\*(Aq. .PP In some cases, the exit mode will depend on the method being called. For example, this module will always execute \f(CW$dbh\fR\->\fBdisconnect()\fR calls against each child handle. .PP In others, the default will be used, unless the user of the DBI specified the \*(Aqmx_exit_mode\*(Aq when connecting, or later changed the \*(Aqmx_exit_mode\*(Aq attribute of a database or statement handle. .SH "USAGE EXAMPLE" .IX Header "USAGE EXAMPLE" Here\*(Aqs an example of using DBD::Multiplex with MySQL\*(Aqs replication scheme. .PP MySQL supports one\-way replication, which means we run a server as the master server and others as slaves which catch up any changes made on the master. Any READ operations then may be distributed among them (master and slave(s)), whereas any WRITE operation must \fIonly\fR be directed toward the master. Any changes happened on slave(s) will never get synchronized to other servers. More detailed instructions on how to arrange such setup can be found at: .PP http://www.mysql.com/documentation/mysql/bychapter/manual_Replication.html .PP Now say we have two servers, one at 10.0.0.1 as a master, and one at 10.0.0.9 as a slave. The DSN for each server may be written like this: .PP .Vb 4 \& my @dsns = qw{ \& dbi:mysql:database=test;host=10.0.0.1;mx_id=masterdb \& dbi:mysql:database=test;host=10.0.0.9;mx_id=slavedb \& }; .Ve .PP Here we choose easy\-to\-remember \f(CW\*(C`mx_id\*(C'\fRs: masterdb and slavedb. You are free to choose alternative names, for example: mst and slv. Then we create the DSN for DBD::Multiplex by joining them, using the pipe character as separator: .PP .Vb 3 \& my $dsn = \*(Aqdbi:Multiplex:\*(Aq . join(\*(Aq|\*(Aq, @dsns); \& my $user = \*(Aqusername\*(Aq; \& my $pass = \*(Aqpassword\*(Aq; .Ve .PP As a more paranoid practice, configure the \*(Aquser\*(Aqs permissions to allow only SELECTs on the slaves. .PP Next, we define the attributes which will affect DBD::Multiplex behaviour: .PP .Vb 5 \& my %attr = ( \& \*(Aqmx_master_id\*(Aq => \*(Aqmasterdb\*(Aq, \& \*(Aqmx_exit_mode\*(Aq => \*(Aqfirst_success\*(Aq, \& \*(Aqmx_shuffle\*(Aq => 1, \& ); .Ve .PP These attributes are required for MySQL replication support: .PP We set \f(CW\*(C`mx_shuffle\*(C'\fR true which will make DBD::Multiplex shuffle the DSN list order prior to connect, and shuffle the .PP The \f(CW\*(C`mx_master_id\*(C'\fR attribute specifies which \f(CW\*(C`mx_id\*(C'\fR will be recognized as the master. In our example, this is set to \*(Aqmasterdb\*(Aq. This attribute will ensure that every WRITE operation will be executed only on the master server. Finally, we call DBI\->\fBconnect()\fR: .PP .Vb 1 \& $dbh = DBI\->connect($dsn, $user, $pass, \e%attr) or die $DBI::errstr; .Ve .SH "LIMITATIONS AND BUGS" .IX Header "LIMITATIONS AND BUGS" A HandleError sub is only invoked on the multiplex handle, not the child handles and can\*(Aqt alter the return value. .PP The Name attribute may change in content in future versions. .PP The AutoCommit attribute doesn\*(Aqt appear to be affected by the begin_work method. That\*(Aqs one symptom of the next item: .PP Attributes may not behave as expected because the DBI intercepts attribute FETCH calls and returns the value, if there is one, from DBD::Multiplex\*(Aqs attribute cache and doesn\*(Aqt give DBD::Multiplex a change to multiplex the FETCH. That\*(Aqs fixed from DBI 1.36. .SH "AUTHORS AND COPYRIGHT" .IX Header "AUTHORS AND COPYRIGHT" Copyright (c) 1999,2000,2003, Tim Bunce & Thomas Kishel .PP While I defer to Tim Bunce regarding the majority of this module, feel free to contact me for more information: .PP .Vb 6 \& Thomas Kishel \& Larson Texts, Inc. \& 1760 Norcross Road \& Erie, PA 16510 \& tkishel@tdlc.com \& 814\-461\-8900 .Ve .PP You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file.