是否可以运行配置为 Hibernate 的应用程序 hbm2ddl.auto=update 在生产环境中更新数据库架构?

有帮助吗?

解决方案

不,这不安全。

尽管Hibernate团队做出了最大的努力,但您无法依靠生产中的自动更新。编写自己的补丁,用DBA查看,测试,然后手动应用。

理论上,如果 hbm2ddl update 在开发中工作,它也应该在生产中工作。但实际上,并非总是如此。

即使它工作正常,也可能是次优的。由于某种原因,DBA的报酬很多。

其他提示

我们在生产中这样做,尽管应用程序不是关键任务,并且员工没有高薪DBA。它只是一个人为错误的手动过程 - 应用程序可以检测到差异并做正确的事情,而且您可能已经在各种开发和测试环境中对其进行了测试。

一个警告 - 在集群环境中,您可能希望避免它,因为多个应用程序可以同时出现并尝试修改可能不好的架构。或者放入一些只允许一个实例更新架构的机制。

Hibernate创建者不鼓励在他们的书籍“Java持久性”中的生产环境中这样做使用Hibernate"

  

警告:我们已经看到Hibernate用户尝试使用SchemaUpdate自动更新生产数据库的架构。这很快就会以灾难告终,您的DBA将不允许这样做。

查看LiquiBase XML以保留更新的更新日志。我从来没有使用它,直到今年,但我发现它很容易学习,并使数据库修订控制/迁移/变更管理非常万无一失。我在Groovy / Grails项目上工作,Grails在其下面使用Hibernate来处理所有ORM(称为“GORM”)。我们使用Liquibase来管理所有SQL架构更改,我们在应用程序随新功能发展的过程中经常这样做。

基本上,您保留了随着应用程序的发展而继续添加的变更集的XML文件。这个文件与你的项目的其余部分一起保存在git(或者你正在使用的任何东西)中。部署应用程序时,Liquibase会检查您要连接的数据库中的更改日志表,以便知道已应用的内容,然后智能地应用文件中尚未应用的任何更改集。它在实践中非常有用,如果您将它用于所有架构更改,那么您可以100%确信您签出和部署的代码将始终能够连接到完全兼容的数据库架构。

令人敬畏的是,我可以在笔记本电脑上使用一个完全空白的slate mysql数据库,启动应用程序,然后立即为我设置架构。它还可以通过首先将这些更改应用于local-dev或staging db来轻松测试模式更改。

开始使用它的最简单方法可能是获取现有数据库,然后使用Liquibase生成初始baseline.xml文件。然后在将来,您可以添加到它并让liquibase接管管理架构更改。

http://www.liquibase.org/

当不知道自己在做什么的人在不应该使用它的情况下使用它时,Hibernate必须放弃关于不使用自动更新的免责声明来掩盖自己。

指出不应该使用它的情况大大超过可以使用的情况。

我已经在很多不同的项目中使用了它多年,从来没有遇到过一个问题。这不是一个蹩脚的答案,而不是牛仔编码。这是一个历史事实。

一个说“从不在生产中做”的人正在考虑一组特定的生产部署,即他熟悉的(他的公司,他的行业等)。

“生产部署”的范围。是多种多样的。

经验丰富的Hibernate开发人员确切知道DDL将从给定的映射配置中产生什么。只要你测试并验证你期望的结果在DDL中(在dev,qa,staging等中),你就可以了。

当您添加许多功能时,自动架构更新可以节省时间。

自动更新无法处理的内容列表是无穷无尽的,但有些例子是数据迁移,添加不可为空的列,列名更改等等。

此外,您需要在群集环境中小心。

但话说回来,如果你知道所有这些东西,你就不会问这个问题了。嗯。 。 。好的,如果你问这个问题,你应该等到你有很多Hibernate和自动架构更新的经验,然后才考虑在prod中使用它。

我会投票否决。当列的数据类型发生更改时,Hibernate似乎不理解。示例(使用MySQL):

String with @Column(length=50)  ==> varchar(50)
changed to
String with @Column(length=100) ==> still varchar(50), not changed to varchar(100)

@Temporal(TemporalType.TIMESTAMP,TIME,DATE) will not update the DB columns if changed

也可能还有其他一些例子,例如将String列的长度超过255并将其转换为text,mediumtext等等。

当然,我认为没有办法“转换数据类型”。无需创建新列,复制数据并吹走旧列。但是,如果您的数据库有不能反映当前Hibernate映射的列,那么您生活得非常危险......

Flyway是处理这个问题的好方法:

http://flywaydb.org

正如我所解释的 本文, ,使用这不是一个好主意 hbm2ddl.auto 在生产中。

管理数据库架构的唯一方法是使用增量迁移脚本,因为:

  • 这些脚本将与您的代码库一起驻留在 VCS 中。当您签出分支时,您将从头开始重新创建整个架构。
  • 增量脚本可以在应用于生产之前在 QA 服务器上进行测试
  • 无需手动干预,因为脚本可以通过以下方式运行 飞道, ,因此它减少了与手动运行脚本相关的人为错误的可能性。

即便是 休眠用户指南 建议您避免使用 hbm2ddl 生产环境的工具。

enter image description here

我不会冒险,因为你最终可能会丢失应该保留的数据。 hbm2ddl.auto = update纯粹是让dev数据库保持最新的简单方法。

我们在一个正在生产的项目中进行了几个月,到目前为止从未出现过问题。请记住此配方所需的2种成分:

  1. 使用向后兼容性方法设计对象模型,即弃用对象和属性,而不是删除/更改它们。这意味着如果您需要更改对象或属性的名称,请保留原有的名称,添加新的名称并编写某种迁移脚本。如果您需要更改对象之间的关联,如果您已经在生产中,这意味着您的设计首先是错误的,因此请尝试考虑一种表达新关系的新方式,而不会影响旧数据。

  2. 部署前始终备份数据库。

  3. 我的感觉是 - 在阅读这篇文章之后 - 参与这次讨论的人中有90%只是想到在生产环境中使用这样的自动化。有些将球扔给了DBA。花一点时间考虑并非所有生产环境都会提供DBA,并且没有多少开发团队能够负担得起(至少对于中等规模的项目)。所以,如果我们谈论的是每个人都必须做所有事情的球队,球就在他们身上。

    在这种情况下,为什么不尝试两全其美?像这样的工具可以提供帮助,通过精心的设计和计划,可以在许多情况下提供帮助。相信我,管理员最初可能很难说服,但如果他们知道球不在他们手上,他们就会喜欢它。

    就个人而言,我永远不会再手工编写脚本来扩展任何类型的架构,但这只是我的观点。在最近开始采用NoSQL无架构数据库之后,我可以看到,所有这些基于模式的操作都将属于过去,因此您最好开始改变您的观点并展望未来。

  • 就我而言(Hibernate 3.5.2、Postgresql、Ubuntu),设置 hibernate.hbm2ddl.auto=update 仅创建新表并在现有表中创建新列。

  • 它既不删除表,也不删除列,也不更改列。它可以被称为一个安全的选择,但是类似 hibernate.hbm2ddl.auto=create_tables add_columns 会更清楚。

这不安全,不推荐,但有可能。

我有在生产中使用自动更新选项的应用程序的经验。

那么,这个解决方案发现的主要问题和风险是:

  • 部署在错误的数据库中. 。如果您错误地在错误的数据库中使用旧版本的应用程序(EAR/WAR/等)运行应用程序服务器...您将有很多新的列、表、外键和错误。数据源文件中的一个简单错误也可能会出现相同的问题(复制/粘贴文件并忘记更改数据库)。总的来说,这种情况对你的数据库来说可能是一场灾难。
  • 应用程序服务器启动时间太长. 。发生这种情况是因为每次启动应用程序时 Hibernate 都会尝试查找所有创建的表/列/等。他需要知道需要创建什么(表、列等)。随着数据库表的增长,这个问题只会变得更糟。
  • 几乎不可能使用的数据库工具. 。要创建与新版本一起运行的数据库脚本,您需要考虑启动应用程序服务器后自动更新将创建什么。例如,如果您需要用一些数据填充新列,则需要启动应用程序服务器,等待 Hibernate 创建新列,然后仅运行 SQL 脚本。正如您所看到的,数据库迁移工具(如 Flyway、Liquibase 等)在启用自动更新的情况下几乎不可能使用。
  • 数据库更改不集中. 。由于 Hibernate 可以创建表和其他所有内容,因此很难在每个版本的应用程序中观察数据库的更改,因为大多数更改都是自动的。
  • 鼓励数据库产生垃圾. 。由于自动更新很容易,您的团队可能会忽略删除旧列和旧表。
  • 灾难迫在眉睫. 。生产中即将发生某种灾难的风险(就像其他答案中提到的一些人)。即使应用程序运行并可更新多年,我也不认为它是安全的。启用此选项后我从未感到安全。

因此,我不会建议在生产中使用自动更新。

如果您确实想在生产中使用自动更新,我建议:

  • 分离的网络. 。您的测试环境无法访问同源环境。这有助于防止本应在测试环境中进行的部署更改认证数据库。
  • 管理脚本顺序. 。您需要组织脚本在部署之前运行(结构表更改、删除表/列)和部署后运行脚本(填充新列/表的信息)。

而且,与其他帖子不同的是,我不认为启用自动更新与“报酬很高”的 DBA 相关(如其他帖子中提到的)...DBA 有比编写 SQL 语句来创建/更改/删除表和列更重要的事情要做。这些简单的日常任务可以由开发人员完成和自动化,并且只传递给 DBA 团队审查,而不需要 Hibernate 和 DBA“高薪”来编写它们。

不,不要这样做。 Hibernate不处理数据迁移。是的,它会使您的架构看起来正确,但它不能确保在此过程中不会丢失有价值的生产数据。

  • 通常,大型组织中的企业应用程序以较低的权限运行。

  • 数据库用户名可能没有 DDL 添加列的权限 hbm2ddl.auto=update 需要。

我同意弗拉基米尔的观点。如果我甚至建议这样的课程,我公司的管理员肯定不会欣赏它。

此外,创建一个SQL脚本而不是盲目信任Hibernate使您有机会删除不再使用的字段。 Hibernate不这样做。

我发现将生产模式与新模式进行比较可以让您更好地了解您在数据模型中发生的变化。当然,你知道,因为你做到了,但现在你可以一次看到所有的变化。甚至那些让你变得像“哎呀!”的那些。

有些工具可以为您制作架构增量,因此它甚至都不是很难。然后你就知道将要发生什么。

应用程序的模式可能会随着时间的推移而演变;如果您有多个安装,并且可能具有不同的版本,那么您应该有某种方法来确保您的应用程序、某种工具或脚本能够将架构和数据从一个版本逐步迁移到任何后续版本。

坚持使用 Hibernate 映射(或注释)是控制模式演变的一个非常好的方法。

您应该考虑模式演化有几个方面需要考虑:

  1. 在添加更多列和表格中,数据库模式的演变

  2. 旧列,表格和关系的下降

  3. 使用默认值填充新列

Hibernate 工具非常重要,特别是在您在许多不同类型的数据库上拥有同一应用程序的不同版本的情况下(就像我的经验一样)。

如果您使用 Hibernate,第 3 点非常敏感,如果您引入一个新的布尔值属性或数字属性,如果 Hibernate 在此类列中发现任何空值,则会引发异常。

所以我要做的是:确实使用 Hibernate 工具的模式更新功能,但您必须同时添加一些数据和模式维护回调,例如填充默认值、删除不再使用的列等。通过这种方式,您可以获得优势(独立于数据库的架构更新脚本,并避免在持久性和脚本中重复编码更新),但您还涵盖了操作的所有方面。

因此,例如,如果版本更新只是添加一个 varchar 值属性(因此是列),该属性可能默认为 null,那么使用自动更新就可以完成。如果需要更多的复杂性,就需要更多的工作。

这是假设应用程序在更新时能够更新其架构(可以完成),这也意味着它必须拥有对架构执行此操作的用户权限。如果客户的政策阻止这种情况(可能是 Lizard Brain 案例),您将必须提供数据库特定的脚本。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top