我有一个庞大的MySQL数据库,让我们调用它live_db
,我想在同一台机器上复制它以提供一个测试系统来解决(test_db
),包括表结构和数据。
我定期以test_db
的内容更新live_db
;如果可能的话增量。
MySQL中是否有一些内置机制可以做到这一点?我认为主从复制不是我想要的,因为它应该可以改变test_db
中的数据。但是,不必保留这些更改。
此致
CGD
答案 0 :(得分:72)
mysql
命令行客户端将接受来自标准输入的SQL语句流。因此,您可以在命令行上将mysqldump
的输出直接传递到mysql
。将此作为cron作业将定期使用更新的实时数据覆盖您的测试数据:
mysql --user=username --password=passwd -e 'DROP DATABASE test_db;'
mysql --user=username --password=passwd -e 'CREATE DATABASE test_db;'
mysqldump --user=username --password=passwd live_db | mysql --user=username --password=passwd test_db
请注意,由于您的数据很大,因此需要很长时间。
答案 1 :(得分:6)
Michaels回答abowe运作良好,但不会复制事件,存储过程或触发器。
要复制那些mysqldump需要更多的开关:
--events --triggers --routines
补充已制作的副本:
mysqldump --user=username --password=passwd --no-data --no-create-info --no-create-db --events --triggers --routines live_db | mysql --user=username --password=passwd test_db
答案 2 :(得分:0)
如果您更喜欢MySQL Migration Toolkit,您可以在数据映射步骤中双击模式名称并更改目标模式名称。
答案 3 :(得分:0)
对于所有mac用户,使用sequel pro,您需要做的只是进入数据库(菜单)->复制数据库。完成!
答案 4 :(得分:0)
MySQLdump的问题在于,在转储时,实时数据库要么不可用,要么使用起来很笨拙,否则备份将不一致。除非您有足够宽的时间窗口,否则实时数据库的不可用性并不重要,因为无论如何都不需要使用该数据库(例如深夜)。
如果您有足够的空间来节省空间-如今20 Gb还不足够-使用辅助数据库。
您可以在另一个端口上安装 MySQL Server的第二个副本,并将其作为从属。然后,您将拥有两个相同的数据库(实时主数据库,实时从数据库)。
当您需要克隆测试数据库时,停止从属复制-活动的从属服务器现在将保持“冻结”状态-并使用MySQLbackup或仅复制数据文件将活动的从属服务器备份到测试数据库。完成后,重新启动复制。
对活动主服务器的影响可以忽略不计,从设备实际上可以用于非更新关键的选择。
答案 5 :(得分:-1)
此解决方案可以正常工作,但如果您使用PHPunit进行单元测试,它将无法完成交易。
在命令行中使用密码会生成一个警告,该警告由PHPUnit捕获并生成异常(是非常重要的......)
解决此问题的方法是使用配置文件。
在我的情况下,我不想在配置文件和PHP代码中维护密码和用户,所以我从代码生成配置文件并检查它是否存在(否则我直接使用用户名和密码)命令行作为后退选项)。
以下是一个示例,在PHP中,如何复制安装数据库以创建具有不同名称的新数据库(例如,如果您为每个客户管理具有不同子域/数据库的主域):
/**
* If the $dbName doesn't exist, then create it.
*
* @param $errorMessage String to return the error message.
* @param $dbName String name of the database to create.
* @param $cleanExisting Boolean if the database exist, clear it to recreate it.
*
* @return boolean ($dbExists)
*/
private function createDatabase(&$errorMessage, $dbName, $clearExisting = false){
$command = "";
$configurationString = "[client]" . "\r\n" . "user=" . parent::$support_user . "\r\n" . "password=" . md5(parent::$support_pass);
$dbExist = false;
$path = realpath(dirname(__FILE__));
$connectionString = " --defaults-extra-file=" . $path . "\mysql.cnf ";
$dbName = strtolower($dbName);
if ($this->isDestinationDbNameValid($errorMessage, $dbName)) {
$dbExist = $this->isDestinationDbExist($errorMessage, $dbName);
if (empty($errorMessage) and ($dbExist === false or $clearExisting === true)) {
if (file_put_contents($path . '/mysql.cnf', $configurationString) === false) {
$connectionString = " --user=" . parent::$support_user . " --password=" . md5(parent::$support_pass). " ";
}
if ($dbExist and $clearExisting) {
$command = $path . '/../../../mysql/bin/mysql ' . $connectionString . ' --execute="DROP DATABASE ' . $dbName .';" &';
}
$command .= '"' . $path . '/../../../mysql/bin/mysql" ' . $connectionString . ' --execute="CREATE DATABASE ' . $dbName . ';" &"' .
$path . '/../../../mysql/bin/mysqldump" ' . $connectionString . ' --events --triggers --routines setup | "' .
$path . '/../../../mysql/bin/mysql" ' . $connectionString . $dbName;
exec($command);
$dbExist = $this->isDestinationDbExist($errorMessage, $dbName);
if (!$dbExist) {
$errorMessage = parent::getErrorMessage("COPY_SETUP_DB_ERR", "An error occurred during the duplication process of the setup database.");
}
}
}
return $dbExist;
}
附加说明:
我必须在我的SQL语句中使用双引号(“)而不是单引号(')。
我不得不使用&符号(&)分隔我的不同命令。
此示例不包括新数据库名称的验证(isDestinationDbNameValid()方法)。无需提及您永远不应该信任用户输入......
您还必须编写自定义方法以验证数据库副本是否按预期工作(isDestinationDbExist()方法)。 您至少应该验证数据库是否存在,您的设置中是否存在表格,并且可以选择验证存储的程序。
明智地使用武力,我的朋友,
来自蒙特利尔的Jonathan Parent-Lévesque