366

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

4

15 回答 15

415

不,这是不安全的。

尽管 Hibernate 团队尽了最大的努力,但您根本不能依赖生产中的自动更新。编写您自己的补丁,与 DBA 一起审查,测试它们,然后手动应用它们。

理论上,如果hbm2ddl 更新在开发中有效,它也应该在生产中有效。但实际上,情况并非总是如此。

即使它工作正常,它也可能不是最理想的。DBA 的薪水这么高是有原因的。

于 2008-10-21T10:41:47.340 回答
71

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

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

于 2008-10-21T11:52:38.697 回答
57

Hibernate 创建者在他们的“Java Persistence with Hibernate”一书中不鼓励在生产环境中这样做:

警告:我们已经看到 Hibernate 用户尝试使用 SchemaUpdate 自动更新生产数据库的模式。这可能很快以灾难告终,并且您的 DBA 不允许这样做。

于 2010-10-01T09:07:21.813 回答
31

查看 LiquiBase XML 以保存更新的变更日志。直到今年我才使用它,但我发现它非常容易学习,并且使数据库修订控制/迁移/变更管理非常简单。我从事一个 Groovy/Grails 项目,Grails 在其所有 ORM(称为“GORM”)下使用 Hibernate。我们使用 Liquibase 来管理所有 SQL 模式更改,随着我们的应用程序随着新功能的发展,我们经常这样做。

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

令人敬畏的是,我可以在笔记本电脑上获取一个完全空白的 mysql 数据库,启动应用程序,然后立即为我设置架构。它还可以通过首先将它们应用于本地开发或暂存数据库来轻松测试模式更改。

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

http://www.liquibase.org/

于 2011-08-13T19:49:30.167 回答
30

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

授予不应该使用它的情况大大超过了可以使用的情况。

我已经在许多不同的项目中使用它多年,并且从未遇到过一个问题。这不是一个蹩脚的答案,也不是牛仔编码。这是历史事实。

一个说“永远不要在生产中这样做”的人正在考虑一组特定的生产部署,即他熟悉的那些(他的公司、他的行业等)。

“生产部署”的范围是广泛而多样的。

经验丰富的 Hibernate 开发人员确切地知道给定映射配置会产生什么 DDL。只要您测试并验证您期望的内容最终会出现在 DDL 中(在 dev、qa、staging 等中),就可以了。

当您添加大量功能时,自动模式更新可以节省大量时间。

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

此外,您还需要注意集群环境。

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

于 2012-09-27T00:53:24.857 回答
29

hbm2ddl.auto在生产中使用不是一个好主意。

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

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

甚至Hibernate 用户指南也建议您避免在hbm2ddl生产环境中使用该工具。

Hibernate ORM 用户指南说得最好

于 2017-06-05T05:33:56.850 回答
27

我会投反对票。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 并看到它转换为文本、中文本等。

当然,我不认为真的有一种方法可以在不创建新列、复制数据和清除旧列的情况下“转换数据类型”。但是,当您的数据库中的列不反映当前的 Hibernate 映射时,您的生活就非常危险......

Flyway 是解决这个问题的一个不错的选择:

http://flywaydb.org

于 2008-12-03T02:45:16.443 回答
9

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

于 2008-10-21T10:44:24.993 回答
8

我们在一个生产运行了几个月的项目中做到了这一点,到目前为止从未出现过问题。请记住此食谱所需的两种成分:

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

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

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

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

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

于 2011-03-10T11:50:19.500 回答
6
  • 在我的情况下(Hibernate 3.5.2、Postgresql、Ubuntu),设置hibernate.hbm2ddl.auto=update只创建了新表并在现有表中创建了新列。

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

于 2013-08-12T05:38:25.267 回答
6

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

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

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

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

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

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

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

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

于 2016-03-30T19:13:05.013 回答
5

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

于 2011-02-15T21:49:17.193 回答
4
  • 通常,大型组织中的企业应用程序以降低的权限运行。

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

于 2009-07-17T05:34:03.860 回答
2

我同意弗拉基米尔的观点。如果我提出这样的课程,我公司的管理员肯定不会感激的。

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

而且我发现将生产模式与新模式进行比较可以让您更好地了解您在数据模型中所做的更改。你知道,当然,因为你做到了,但现在你一口气看到了所有的变化。甚至那些让你喜欢“这到底是什么?!”的人。

有一些工具可以为您制作模式增量,所以这甚至不是艰苦的工作。然后你就知道会发生什么。

于 2008-10-21T17:40:09.430 回答
2

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

将所有持久性保留在 Hibernate 映射(或注释)中是控制模式演变的一种非常好的方法。

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

  1. 数据库模式在添加更多列和表方面的演变

  2. 删除旧列、表和关系

  3. 用默认值填充新列

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

第 3 点在您使用 Hibernate 的情况下非常敏感,因为如果您引入新的布尔值属性或数字属性,如果 Hibernate 会在此类列中找到任何空值,则会引发异常。

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

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

这是假设应用程序在更新时能够更新其模式(可以这样做),这也意味着它必须具有对模式执行此操作的用户权限。如果客户的政策阻止了这种情况(可能是蜥蜴脑案例),您将必须提供特定于数据库的脚本。

于 2010-04-26T19:47:13.583 回答