MySQL多服务器批量执行SQL脚本

3 月 10th, 2010 | Posted by | Filed under 程序设计

本文内容遵从CC版权协议, 可以随意转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明
网址: http://www.penglixun.com/tech/program/mysql_bat_sql_script_mybatsql.html

主要应用场景是,假设我们有一个库DB进行了水平拆分,DB1~10都需要更改表结构,如果手动到各个服务器去执行,效率太低,写了个脚本来做这个事情,叫mybatsql。

用法很简单,需要两个文件,server.list和sql.list,跟脚本放在同一目录下。
server.list中放服务器的主机名/IP,用户名,密码;sql.list中放需要批量执行的SQL
例如:
server.list

127.0.0.1,root,111
127.0.0.2,root,111

sql.list

show status;
show variables;

这两个文件表示,我要在127.0.0.1和127.0.0.2上执行show status;show variables;语句。

也可以通过参数-l/-s指定这两个文件的地址:perl mybatsql.pl -l server_server_file -s sql_file

  mybatsql.pl (4.1 KiB, 2,884 hits)


#!/usr/bin/perl -w
#######################################################
# Create: P.Linux
# Function: Run DDL On Server List
# Usage: Run on any computer with Perl
# License: GPL v2
# Site: PengLiXun.COM
# Modify: 
# P.Linux 2010-03-10 
#    -Create 1.0 Release
########################################################
use strict;
use DBI;
use DBD::mysql;
use Getopt::Std;
use vars qw($opt_l $opt_s);
########################################################
# Global Status Var
# 全局状态变量
my @server_list;
my $sql;
# Connect to database via DBI
# 通过DBI连接数据库
my @dbconn;

# CmdLine Option vars
# 命令行参数变量
my($server_file, $sql_file);

# Version
my $version='1.0 Release';

#######################################################
# Main Program
# 主程序
#######################################################

# Get CmdLine Options
# 获取命令行参数
&get_option();

# Read Server List From File
# 从文件中读取服务器列表
&read_file();

# Crate MySQL Database Connect
# 创建MySQL数据库连接
&create_conn();

# Run SQL
# 执行SQL
&run();

# Disconnect from MySQL
# 从数据库断开连接
&close_conn();

#######################################################
# Print Usage
# 打印使用方法
#######################################################
sub print_usage () {
        printf <<EOF
 NAME:
        mybatsql

 SYNTAX:
        mybatsql  -l server_server_file -s sql_file

 FUNCTION:
        Run SQL on Server List

 PARAMETER:
      -l   Database Server List File DEFAULT:server.list
      -s   SQL File DEFAULT:sql.list
EOF
}

#######################################################
# Get Options
# 获取命令行参数
#######################################################
sub get_option(){
    my $rtn = getopts('l:s');
    unless ( "$rtn" eq "1" ) { print_usage(); exit 1;}

    $server_file=$opt_l?$opt_l:'server.list';
    $sql_file=$opt_s?$opt_s:'sql.list';

    if($ARGV[0]){
        $server_file=$ARGV[0];
    }
    if($ARGV[1]){
        $sql_file=$ARGV[1];
    }

    $server_file = lc($server_file);
    $sql_file = lc($sql_file);
}

#######################################################
# Read Server List & SQL From File
# 从文件中读取服务器列表和SQL。
#######################################################
sub read_file{
    my $i;

    # Read Server List File
    open(FILE,"$server_file");
    $i = 0;
    while(){
        chomp;
        $server_list[$i] = [split(/,/,$_)];
	    $i++;
    }
    close(FILE);
    # Read SQL List File
    open(FILE,"$sql_file");
    $i = 0;
    $sql = '';
    while(){
	    chomp;
	    $sql .= $_;
	    $i++;
    }
    close(FILE);
}

#######################################################
# Create MySQL Database Connect 
# 创建MySQL数据库连接
#######################################################
sub create_conn{
    my $i = 0;
    foreach my $server (@server_list){
	    my @srv = @{$server};
	    my $host = $srv[0];
	    my $user = $srv[1];
	    my $pwd = $srv[2];
        #print "$host.$user.$pwd\n";
        eval{
            local $SIG{ALRM} = sub { die "连接数据库超时\n" };
            alarm 20;
            $dbconn[$i] = DBI->connect("DBI:mysql:host=$host", $user, $pwd, {'RaiseError' => 1}) 
            or die "Connect to $host error:". DBI->errstr;
            alarm 0;
        };   
        if($@){
            printf "Connect to $host database error:".$@."\n";
            exit;
        }
        $i++;
    }
}

#######################################################
# Main Program to Run SQL on Server List
# 在服务器列表上执行一组SQL
#######################################################
sub run{
    foreach my $conn (@dbconn) {
        #print $sql;
        $conn->do($sql); 
        $conn->commit(); 
    }
}

#######################################################
# Disconnect from MySQL
# 从数据库断开连接
#######################################################
sub close_conn(){
    foreach my $conn (@dbconn) {
        $conn->disconnect;
    }
}
  1. nettedfish
    4 月 20th, 201010:50

    不错.我也写了一个,就是把sql文件通过信任关系scp到目标主机上,然后执行,执行完毕后删除,返回确认后再操作下一台.

    [回复]