我有点惊讶地发现,DDL语句(alter table
,create index
等)隐含在MySQL提交当前事务。来自MS SQL Server,能够在本地事务中进行数据库更改(然后被回滚)的能力是我工作流程的重要组成部分。对于连续集成,如果由于某种原因导致迁移失败,则使用回滚,以便至少我们不会使数据库处于半迁移状态。
人们在将MySQL与迁移和持续集成结合使用时如何解决这两个问题?
我有点惊讶地发现,DDL语句(alter table
,create index
等)隐含在MySQL提交当前事务。来自MS SQL Server,能够在本地事务中进行数据库更改(然后被回滚)的能力是我工作流程的重要组成部分。对于连续集成,如果由于某种原因导致迁移失败,则使用回滚,以便至少我们不会使数据库处于半迁移状态。
人们在将MySQL与迁移和持续集成结合使用时如何解决这两个问题?
Answers:
对于许多人来说,MySQL Achilles的缺点是隐式提交。
根据该书第418页第3段
以下命令可以并且将中断交易
ALTER TABLE
BEGIN
CREATE INDEX
DROP DATABASE
DROP INDEX
DROP TABLE
RENAME TABLE
TRUNCATE TABLE
LOCK TABLES
UNLOCK TABLES
SET AUTOCOMMIT = 1
START TRANSACTION
对于MySQL,您构造的任何ContinuousIntegration(CI)/ SelfService作业都应始终使事务性作业和DDL脚本互斥。
这为您提供了创建范例的机会,
START TRANSACTION/COMMIT
区块正确隔离的交易警告:如果您正在使用MyISAM进行此操作,则可以(不)将MyISAM添加到可能中断事务的事物列表中,可能不是隐式提交,而是绝对要在数据一致性方面进行回滚需要。
LVM快照非常有用,并且理想的是恢复数据库的整个实例而不必执行繁重的SQL处理。但是,对于MySQL,您必须考虑两个存储引擎:InnoDB和MyISAM。
看看InnoDB的体系结构(图片由Percona CTO Vadim Tkachenko提供)
InnoDB有很多活动的部分
拍摄所有InnoDB数据库的LVM快照,并在缓冲区池和内存缓存中浮动未提交的更改,这将产生一个数据集,一旦恢复LUN并启动mysqld,该数据集将需要InnoDB崩溃恢复。
SET GLOBAL innodb_fast_shutdown = 0;
SET GLOBAL innodb_max_dirty_pages_pct = 0;
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';
service mysql stop
service mysql stop
SET GLOBAL innodb_max_dirty_pages_pct = 0;
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';
SET GLOBAL innodb_max_dirty_pages_pct = 75;
当访问MyISAM时,将维护针对它的打开文件句柄数。如果MySQL崩溃,则任何打开文件句柄计数> 0的MyISAM表都将被标记为崩溃,需要修复(即使数据没有问题)。
还原快照并启动mysqld时,对使用MyISAM表的数据库进行LVM快照将需要修复一个或多个MyISAM表。
SET GLOBAL innodb_fast_shutdown = 0;
SET GLOBAL innodb_max_dirty_pages_pct = 0;
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';
service mysql stop
service mysql stop
您可以强制刷新某些InnoDB表
SET GLOBAL innodb_max_dirty_pages_pct = 0;
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';
FLUSH TABLES innodb_tbl1,... FOR EXPORT;
在关键的InnoDB表上运行FLUSH TABLES WITH READ LOCK;
UNLOCK TABLES;
SET GLOBAL innodb_max_dirty_pages_pct = 75;
虽然您可以将一个LVM快照还原到两台服务器并设置MySQL Master / Slave Replication,但在还原快照时,这将成为清理房间的额外来源。
如果在主服务器上运行CI作业而这些作业很小,则在某些情况下复制可能会节省时间。您可以STOP SLAVE;
在从站上运行START SLAVE;
,在主服务器上启动CI作业,然后在验证主站数据后在从站上运行。
如果CI作业警告了太多数据,则可以从头还原LVM快照并设置复制。如果您发现自己经常这样做,则可以设置MySQL复制。
如果您谈论持续集成,那么我认为这是一个开发环境。在那种情况下,我想说做结构更改的人必须测试它们,以确保不会破坏他人的工作,就像更新公用库的人一样:在提交此类更改之前,请在您自己的沙箱中进行测试。
在生产部署过程中,您通常会经历开发,QA甚至生产前环境来测试您的更改,就像对任何代码更改一样。
请注意,这并非特定于MySQL:Oracle数据库在发出“ alter table”等内容时也会隐式执行COMMIT。
现在,如果您想保护自己,那么您当然可以事先进行备份,或者,如果系统可以这样做,则可以进行LVM或文件系统快照。您也可能有一个从站,为了安全起见,您可以在敏感操作之前将其延迟/停止。