我们如何管理对生产数据库的架构升级?
这似乎是一个可以真正利用一些见解的领域。最佳做法是:
- 进行升级程序
- 出现错误时退后
- 同步代码和数据库更改
- 部署前进行测试
- 修改表的机制
等等...
解决方案
回答
通常,我的规则是:"应用程序应管理自己的模式。"
这意味着架构升级脚本是该应用程序的任何升级包的一部分,并在应用程序启动时自动运行。如果发生错误,则应用程序无法启动,并且升级脚本事务未提交。不利的一面是应用程序必须具有对架构的完全修改访问权限(这使DBA感到烦恼)。
使用Hibernates SchemaUpdate功能来管理表结构已经取得了很大的成功。保留升级脚本以仅处理实际数据初始化和偶尔删除列(SchemaUpdate不会这样做)。
关于测试,由于升级是应用程序的一部分,因此对其进行测试成为应用程序测试周期的一部分。
事后思考:在这里接受其他评论中的一些批评时,请注意该规则说"这是自己的"。它仅在应用程序拥有架构的情况下才真正适用,通常与作为产品出售的软件一样。如果软件与其他软件共享数据库,请使用其他方法。
回答
我是Red Gate产品的忠实拥护者,这些产品有助于创建SQL包来更新数据库架构。可以将数据库脚本添加到源代码管理中,以帮助进行版本控制和回滚。
回答
这是个好问题。 (很有可能这将导致规范化与非规范化的数据库辩论。.我不会开始……现在可以进行一些输入了。)
我已经做了一些事(当我有更多时间或者需要休息时,将会增加更多的事情)
在客户端设计中,这是内联sql的VB方法(即使有准备好的语句)也会给我们带来麻烦。我们可以花费AGES来查找这些语句。如果我们使用Hibernate之类的东西并将大量的SQL放入命名查询中,那么对于大多数sql来说,它只有一个位置(没有比尝试测试某些IF语句中的sql更糟糕的了,我们只需按一下"触发器"即可)该IF语句的测试标准)。在我直接在JDBC或者ODBC中执行SQL时,使用休眠(或者其他orms)之前,我会将所有sql语句放置为对象的公共字段(具有命名约定)或者属性文件(也具有命名)值的约定表示PREP_STMT_xxxx,并在启动时在值上使用反射或者迭代a)测试用例b)应用程序的启动(某些rdbms允许我们在执行之前用准备好的语句进行预编译,所以在启动后登录I会在启动时预编译prep-stmts以使应用程序进行自我测试,即使在一个好的rdbms上执行100条语句也只需几秒钟,也只有一次,这节省了我很多时间。在一个项目中,DBA的不会进行交流(在不同国家/地区的另一个团队),并且该模式似乎无缘无故地发生了变化,而且每天早晨,我们都会获得启动时确切地在哪里破坏了应用程序的列表。
如果需要临时性功能,请将其放在一个命名良好的类中(即再次使用命名约定来帮助进行自动匹配测试),该类充当查询的某种工厂(即,它构建查询)。无论如何,我们都将不得不编写等效的代码,只需将其放置在可以测试它的地方即可。我们甚至可以在同一对象或者单独的类中编写一些基本的测试方法。
如果可以的话,也请尝试使用存储过程。如上所述,它们很难测试。某些数据库也不会在编译时仅在运行时针对架构对存储的proc中的sql进行预验证。通常,这涉及说要获取模式结构的副本(无数据),然后针对该副本创建所有存储的proc(以防数据库团队进行的更改未正确验证)。因此可以检查结构。但是作为变更管理的一个方面,存储的proc很棒。改变就得到它。特别是在数据库更改是业务流程更改的结果时。以及所有语言(java,vb等均可更改)
我通常还会设置一个我使用的表,称为system_setting等。在此表中,我们保留一个VERSION标识符。这样,客户端库就可以连接并验证它们对于此版本的架构是否有效。根据架构的更改,如果客户端可以破坏架构,则不希望它们允许连接(即,我们在数据库中没有很多引用规则,但是在客户端上)。这取决于我们是否还要具有多个客户端版本(在NON Web应用程序中确实发生,即它们运行的二进制文件错误)。我们也可以使用批处理工具等。我也做过的另一种方法是在某种类型的属性文件中或者在system_info表中再次定义一组用于操作版本的模式。该表在登录时加载,然后由每个"经理"(我通常使用某种客户端api来执行大多数数据库工作)来验证该操作(如果它是正确的版本)。因此,大多数操作可以成功,但是我们也可以对过时的方法失败(引发一些异常),并告诉我们原因。
管理对架构的更改->是否更新表或者将1-1关系添加到新表?由于这个原因,我已经看到很多商店总是通过视图访问数据。这允许更改表名,列等。我一直在考虑将视图实际上视为COM中的接口之类的想法。 IE。我们可以为新功能/版本添加新的VIEW。通常,让我们进入这里的是,我们可以有许多采用表格格式的报告(尤其是最终用户自定义报告)。该视图允许我们部署新的表格格式,但支持现有的客户端应用程序(记住所有那些讨厌的临时报告)。
另外,需要编写更新和回滚脚本。一次又一次的测试,测试,测试...
-----------好的,这是位随机讨论的时间--------------
实际上有一个大型商业项目(即软件商店),但我们也遇到了同样的问题。该体系结构为2层,他们使用的产品有点像PHP,但低于PHP。一样。不同的名字。无论如何,我进来的是版本2.
升级花了很多钱。很多。 IE。放弃数周的免费现场咨询时间。
到了要添加新功能或者优化代码的地步。现有的一些代码使用存储过程,因此我们在共同点上可以管理代码。但其他方面是html中的嵌入式SQL标记。这对于快速进入市场非常有用,但是每次进行新功能交互时,测试和维护成本至少翻了一番。因此,当我们考虑拉出php类型代码,放入数据层(这是2001-2002,在任何ORM之前)以及添加许多新功能(客户反馈)时,就着眼于如何设计升级的问题进入系统。这很重要,因为升级要花费很多钱才能正确完成。现在,大多数模式和所有其他人员都在一定程度上讨论正在运行的OO代码,但事实是数据必须a)集成到此逻辑中,b)含义和结构数据可能随时间而变化,并且通常是由于数据的工作方式,最终导致客户组织中需要数据的大量子流程/应用程序->临时报告或者任何复杂的自定义报告以及批处理作业对于自定义数据Feed等已完成的操作
考虑到这一点,我开始玩一些剩余的东西。它还有一些假设。 a)数据被大量读取而不是写入。 b)确实会发生更新,但不会在银行级别上发生,即。一秒钟或者一秒钟说一声。
想法是将COM /接口视图应用于客户端如何通过一组CONCRETE表(随模式更改而变化)访问数据的方式。我们可以为每种类型操作的更新,删除,插入和读取创建单独的视图。这个很重要。这些视图或者直接映射到表,或者允许我们触发进行实际更新或者插入等操作的虚拟表。我真正想要的是某种可捕获的级别间接访问,它们仍然可以由Crystal报表等使用。注意对于inserts,update和delete,我们还可以使用存储的proc。我们为产品的每个版本都有一个版本。这样,1.0版将具有其架构的版本,并且如果表发生更改,我们仍将具有1.0版的VIEWS,但是具有需要根据需要映射到新表的NEW后端逻辑,但是我们也具有将支持的2.0版视图新字段等。这实际上仅是为了支持即席报告,如果我们是业务人员而不是编码员,那么这可能就是我们购买该产品的全部要点。 (产品可以说是废话,但如果我们拥有世界上最好的报告,我们仍然可以赢,相反,产品可以说是最好的功能,但是如果报告的情况更糟,则我们很容易松懈)。
好吧,希望其中一些想法有所帮助。
回答
这些都是很重要的话题,但这是我的更新建议。
我们没有指定平台,但是对于NANT构建环境,我使用Tarantino。对于我们准备提交的每个数据库更新,请制作一个更改脚本(使用RedGate或者其他工具)。当我们开始生产时,Tarantino会检查脚本是否已在数据库上运行(它将表添加到数据库中以进行跟踪)。如果不是,则运行脚本。它不需要管理数据库版本就可以进行所有手动工作(阅读:人为错误)。
回答
liquibase.org:
- 它了解休眠定义。
- 它比休眠生成更好的架构更新sql
- 它记录对数据库进行了哪些升级
- 它处理两步更改(即删除列" foo",然后将其他列重命名为" foo")
- 它处理有条件升级的概念
- 开发人员实际上是在听社区(如果我们不在"人群中"或者新手中,请保持休眠状态-我们基本上会被忽略。)
http://www.liquibase.org
回答
观点
应用程序永远不要处理架构更新。这是一场灾难,等待发生。数据使应用程序持久化,并且一旦多个应用程序尝试使用相同的数据(例如生产应用程序+报告应用程序),可能是它们都将使用相同的基础公司库...然后两个程序都决定这样做他们自己的数据库升级...玩得一团糟。
回答
我听说过有关iBATIS 3 Schema Migrations System的一些好消息:
用户指南:http://svn.apache.org/repos/asf/ibatis/java/ibatis-3/trunk/doc/en/iBATIS-3-Migrations.pdf
回答
正如Pat所说,请使用liquibase。尤其是当我们有几个拥有自己的开发数据库的开发人员时
进行更改,这些更改将成为生产数据库的一部分。
如果只有一个开发人员,例如我现在在一个项目上,我只是将模式更改作为SQL文本文件提交到CVS存储库中,当代码更改进入时,我在生产服务器上分批签出。
但是liquibase的组织性比这更好!