2008-09-08 16 views
2

在我们当前的数据库开发环境中,我们使用自动构建过程检查svn create database脚本中的所有sql代码,并将它们应用于各种开发/ qa数据库。重新运行数据库开发脚本

这是一切都很好,是一个tremdous改善了我们过去一样,但我们有一个问题,重新运行的脚本。很显然,这对于像改变程序这样的一些脚本来说不是问题,因为你可以一遍又一遍地运行它们而不会不利地影响系统。现在添加元数据并运行像create/alter table语句之类的语句,我们添加代码来检查并查看对象是否存在,如果存在,请不要运行它们。

我们的问题是,我们真的只有一次机会来运行脚本,因为一旦脚本已经运行时,物体在环境中,系统不会再次运行该脚本。如果一旦部署后需要更改某些内容,我们就有一个难以运行更新脚本的过程,即更新脚本,希望所有内容都按照正确的顺序排列,并且所有的PK都在环境之间排队(数据库是,我们应该说,“特别”)。

短删除数据库和从头开始的过程(最后一个最新版本)的,没有任何人有一个更优雅的解决方案呢?

回答

1

你保留现有的数据库中的数据?如果没有,你可能想看看类似于马特提到的.NET一些所谓RikMigrations

http://www.rikware.com/RikMigrations.html 

我用我的项目更新我的飞行数据库,同时跟踪修订。此外,它对数据库架构移动到不同的服务器,它很简单,等

如果你想拥有重新流动性在脚本
0

,那么你不能让他们为定义......我的意思是这个是你需要关注更改脚本而不是这里是我的表脚本。

让我们假设你有一个表的客户:

create table Customers (
    id int identity(1,1) primary key, 
    first_name varchar(255) not null, 
    last_name varchar(255) not null 
) 

,以后你要添加一个状态栏。不要修改原始表脚本,该脚本已经运行(并且可以使用if(!exists)语法来防止它在再次运行时导致错误)。

相反,有一个新的脚本,在这个脚本调用add_customer_status.sql

你必须是这样的:(!存在)

alter table Customers 
add column status varchar(50) null 

update Customers set status = 'Silver' where status is null 

alter table Customers 
alter column status varchar(50) not null 

同样,你可以用,如果这个包起来,以阻止允许重新运行,但在这里我们已经利用了这是一个改变脚本的概念,并且我们相应地调整了数据库。如果客户表中已有数据,那么我们仍然可以,因为我们添加了列,使用数据对其进行种子处理,然后添加非空约束。

上述两种迁移框架都很好,我也有很好的经验与MigratorDotNet

0

Scott命名了几个其他SQL tools,这解决了变更管理的问题。但我仍然在摇摆我自己。

我想回答这个问题,并添加我的困惑,仍然没有免费的,基于社区的工具来解决这个问题。显然,脚本并不是维护数据库模式的令人满意的方式;也不是实例。那么,为什么我们不要将元数据保存在单独的(而我们处于这个平台中的情况下)格式呢?

这就是我现在要做的。我的主数据库模式是一个版本控制的XML文件,最初由一个简单的Web服务创建。一个简单的javascript程序将实例与它进行比较,而简单的XSL转换就会产生CREATE或ALTER语句。它有限制,如RikMigrations;例如它并不总是正确地对顺从的对象进行排序。 (但是猜猜也不是Microsoft's SQL Server Database Publication tool。)真的,这太简单了。我根本没有包含我没有使用的对象(角色,用户等)。

所以,我认为这个问题确实没有得到充分的解决,迟早我们必须聚在一起解决恶魔般的细节问题。

2

我们解决这个问题 - 或至少相似的问题这一点 - 如下:

  1. 架构的版本号 - 这是由具有每个版本一列一个表,其除了作为代表版本号,携带枯燥的东西,如该版本出现时的日期/时间戳。
  2. 通过让模式创建/修改包含在代码中的DDL来为我们执行更改。

在上面的上下文中,将构建模式更改代码作为构建过程的一部分,然后运行它,它只会应用尚未应用的模式更改。在大多数情况下,模式变化足够小/快,以致它们可以安全地在事务中运行,这意味着如果失败,我们会得到一个回滚,而数据库是“安全” - 尽管在可行的情况下总是建议在应用模式更新之前进行备份。

我从恶劣的痛苦经历中发展而来。它不是一个完美的系统(或一个原始的想法),但是作为这种工作方式的结果,我们有很高的信心,如果我们的一个数据库有两个相同版本的实例,那么这两个数据库的模式将会在几乎所有方面都是一样的,我们可以安全地将任何db带到该应用程序的当前模式,而不会产生不良影响。 (不幸的是,最后并不是100%真的 - 总是有一个例外 - 但是它的真相并不太远!)

0

我们进行了“删除并重新创建模式”路线。我们在JUnit测试包中有一些类,它们将脚本参数化,以便为执行代码的开发人员在模式中创建所有对象。这使得所有开发人员可以共享一个测试数据库,每个人都可以同时创建/测试/丢弃他们的测试表而不会发生冲突

运行需要很长时间吗?是。起初,我们使用了这种设置方法,这意味着每个测试都会丢弃/创建表,并且这个过程太长了。然后我们创建了一个TestSuite,它可以在所有类的测试之前运行一次,然后在所有类测试完成后清理干净。这仍然意味着当我们运行包含我们所有软件包中的所有测试的'AllTests'类时,db安装程序运行很多次。我解决这个问题的方法是在OracleTestSuite代码中添加一个信号量,因此当第一次测试请求数据库进行安装时,它会这样做,但后续任何调用只会增加一个计数器。当每个tearDown()方法被调用时,计数器将递减计数器直到它达到0,并且OracleTestSuite代码将丢弃所有内容。留下的一个问题是测试是否假定数据库是空的。让数据库测试知道它们的运行顺序是很方便的,这样可以利用数据库的状态,因为它可以减少数据库设置的重复。

我们使用ObjectMothers的概念解决了创建复杂域对象以用于测试目的的类似问题。模拟对象可能是更好的答案,但我们当时没有听说过它们。毕竟这一次,我建议创建测试助手方法,可以为典型场景创建标准化数据集。此外,这将有助于从数据角度记录重要的边缘案例。