live_db
,我想在同一台机器上复制它来提供一个测试系统来进行操作(test_db
),包括表结构和数据。
我希望定期更新test_db
内容与live_db
相同;如果可能的话是增量更新。MySQL中是否有一些内置的机制可以实现这个功能?我认为主从复制不是我想要的东西,因为应该可以更改
test_db
中的数据。虽然这些更改不必得到保留。live_db
,我想在同一台机器上复制它来提供一个测试系统来进行操作(test_db
),包括表结构和数据。
我希望定期更新test_db
内容与live_db
相同;如果可能的话是增量更新。test_db
中的数据。虽然这些更改不必得到保留。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
请注意,由于您的数据很大,所以需要花费很长时间。orig_db
”语句,这样您就无法将数据写入到右侧指定的数据库中。我曾经吃过这个亏。:-/ - bradoaks迈克尔上面的答案很好,但它不会复制事件、存储过程或触发器。
为了复制这些内容,需要在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
我已经在不同的环境中做了几年这个,用于小到中型数据库(1G到100G)。对于较小的数据集,快速而简单的mysqldump
可以胜任;它们越小,备份效果就越好。
但当你超过5-10 GB时,根据MySQL负载情况,这种快速而简单的方法就不再够用了。
mysqldump
可能不够用MySQLdump的问题在于,在转储期间,实时数据库要么无法使用,要么非常难以使用,或者备份将不一致。除非您有足够长的时间窗口,使得实时数据库的不可用性是不重要的,因为无论如何数据库都不需要使用 (例如在深夜)。
默认选项(这里讨论了原因)会使数据库在转储时几乎无法使用,除非只是读取数据,且数据量很少。在繁忙的电子商务网站上,您将看到客户堆积导致崩溃。
因此,您应该使用InnoDB和现代选项(不是默认选项,据我所知)。
--single-transaction --skip-lock-tables
在转储期间,这些允许网站运行,尽管比正常情况下慢,根据使用情况不同,可能会明显变慢。
同时,将可能重要的其他数据一并转储:
--events --triggers --routines
(...噢,这仍然不会转储用户权限。作为测试使用可能并不那么重要)。
我发现了一个“建议”的绕过方法,它基本上禁用了事务完整性,允许数据库在转储时以全速运行。有点像从汽车中拆掉制动器来减轻重量并使其跑得更快,是的它会奏效,但它会有一些你可能无法立即注意到的副作用。您几乎肯定迟早会注意到它们 - 就像刹车一样,当您最需要它们时,它们将变得非常重要,而且情况并不好。
但是,对于测试数据库,它仍然可以工作。
如果您有一个“严肃”的数据库,为什么不拥有“严肃”的备份呢?
如果您有足够的空间 - 而现在,20 Gb 并不算太多 - 另一个可能性就是使用辅助数据库。
您可以在同一台服务器上安装MySQL Server的第二个副本,使用不同的端口,并使其成为从服务器 (服务器将受到性能影响,存储速度方面)。然后您将拥有两个相同的数据库 (活动主服务器,活动从服务器)。 第一次,您仍然需要运行完整转储才能让它们同步,带来所有涉及的问题。
当您需要克隆测试数据库时,请停止从服务器复制 - 活动从服务器现在将保持“冻结”状态 - 并将活动从服务器备份到测试数据库,使用MySQLbackup或仅复制数据文件。完成后,您重新启动复制。
对活动主服务器的影响可以忽略不计,而且从服务器实际上可以用于非更新关键查询。
如果您喜欢使用MySQL迁移工具包,您可以在数据映射步骤中双击模式名称并更改目标模式名称。
对于所有的Mac用户,使用Sequel Pro,你只需要进入数据库(菜单)-> 复制数据库。完成!
这个解决方案很好用,但如果您正在使用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
auto_increment
键,那么可以设置复制,但大部分时间保持从服务器处于停止状态。然后定期使用START SLAVE;
命令,使其更新到最新状态。但是,如果您有任何auto_increment
字段,则会导致键冲突。 - Michael Berkowski