休眠:hbm2ddl.auto =生产中更新?

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

不,这是不安全的。

尽管Hibernate团队付出了最大的努力,但您不能依靠生产中的自动更新。 编写你自己的补丁,用DBA检查它们,测试它们,然后手动应用它们。

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

即使它运作良好,也可能是次优的。 数据库管理员支付那么多的原因。

我们在生产中做到这一点,尽管应用程序不是关键任务,而且员工也没有高薪的DBA。 这只是一个人为错误的手动过程 – 应用程序可以检测到差异并做正确的事情,再加上大概在不同的开发和测试环境中进行测试。

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

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

警告:我们已经看到Hibernate用户试图使用SchemaUpdate自动更新生产数据库的模式。 这可能会很快结束,不会被DBA所允许。

查看LiquiBase XML以保持更新的更新日志。 直到今年我才使用过它,但是我发现这很容易学习,并且使DB版本控制/迁移/变更管理变得非常简单。 我在Groovy / Grails项目上工作,Grails使用Hibernate的所有ORM(称为“GORM”)。 我们使用Liquibase来管理所有的SQL模式更改,我们经常在应用程序随着新功能的发展而进行更改。

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

真棒的是,我可以在我的笔记本电脑上采取一个完全空白的石板mysql数据库,启动应用程序,并立即架构为我设置。 通过首先将它们应用于本地-dev或分段数据库,也可以轻松地测试模式更改。

开始使用它最简单的方法可能是取现有的数据库,然后使用Liquibase生成一个初始baseline.xml文件。 那么在将来你可以追加到它,让liquibase接管管理模式的变化。

http://www.liquibase.org/

我会投不。 当列的数据类型发生改变时,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

当不知道自己在做什么的人在不应该使用它的情况下,Hibernate必须放弃在prod中不使用自动更新的声明来掩饰自己。

给予不应该被大量使用的情况比可以使用的情况要少得多。

我在很多不同的项目上使用了很多年,从来没有一个单一的问题。 这不是一个蹩脚的答案,这不是牛仔编码。 这是一个历史事实。

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

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

一位经验丰富的Hibernate开发人员确切知道给定的映射配置会产生哪些DDL。 只要你测试和验证你期望的结果在DDL(在开发,QA,分期等),你没事的。

当您添加大量功能时,自动架构更新可以成为一个真正的节省时间。

东西自动更新不会处理的列表是无止境的,但一些例子是数据迁移,添加不可空列,列名称更改等。

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

但是再一次,如果你知道所有这些东西,你就不会问这个问题。 嗯。 。 。 好的,如果你问这个问题,你应该等到你有很多关于Hibernate和自动模式更新的经验之后才考虑在产品中使用它。

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

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

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

  • 这些脚本将在您的代码库中驻留在VCS中。 当你签出一个分支时,你从头开始重新创建整个模式。
  • 增量脚本可以在QA服务器上进行测试,然后才能在生产环境中使用
  • 由于脚本可以由Flyway运行,因此不需要手动干预,因此可以减少与手动运行脚本相关的人为错误。

即使“ Hibernate用户指南”也建议您避免在生产环境中使用hbm2ddl工具。

在这里输入图像描述

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

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

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

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

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

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

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

  • 在我的情况下(Hibernate 3.5.2,Postgresql,Ubuntu),设置hibernate.hbm2ddl.auto=update只创建新表,并在已经存在的表中创建新的列。

  • 它既没有删除表,也没有删除列,也没有改变列。 它可以被称为一个安全的选项,但像hibernate.hbm2ddl.auto=create_tables add_columns会更清晰。

这是不安全的,不推荐,但是这是可能的。

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

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

  • 部署在错误的数据库中 。 如果在错误的数据库中提交错误的应用程序服务器运行旧版本的应用程序(EAR / WAR / etc)…你会有很多新的列,表,外键和错误。 同样的问题可能发生在数据源文件中的一个简单的错误,(复制/粘贴文件,忘记更改数据库)。 在简历中,情况可能是数据库中的灾难。
  • 应用程序服务器启动时间过长 。 发生这种情况是因为Hibernate在每次启动应用程序时尝试查找所有创建的表/列/等。 他这样做是为了知道需要创建什么(表格,列等)。 这个问题只会变得更糟。
  • 数据库工具几乎不可能使用 。 要为数据库创建脚本,您需要考虑启动应用程序服务器后自动更新所创建的内容。 如果需要用一些数据填充一个新列(每个示例),则需要启动应用程序服务器,等待Hibernate创建新列并在此之后运行SQL脚本。 像Flyway这样的工具几乎不可能在启用自动更新的情况下使用。
  • 数据库更改不是集中式的 。 有了Hibernate创建表和其他东西的可能性,很难在应用程序的每个版本中都看到数据库的变化,因为它们大部分是自动的。
  • 鼓励数据库上的垃圾 。 由于自动更新的简易性,您的团队有可能会忽略掉旧列和旧表。
  • 即将发生的灾难 。 生产中即将发生一些灾难的风险(如其他答案中提到的一些人)。 即使使用多年的应用程序运行和更新,我也不认为它是安全的。 我从来不觉得安全。

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

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

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

另外,不同的职位,我不认为自动更新启用它与薪酬相当好的DBA有关… DBA比编写SQL语句创建/更改/删除表和列更重要的事情要做。 这些简单的日常任务可以由开发人员完成并自动化,只有通过DBA团队审核才能完成,而不需要Hibernate和DBA很高的薪水来编写它们。

我同意弗拉基米尔。 如果我甚至建议这样的课程的话,我公司的管理员肯定不会感激。

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

我发现将生产模式与新模式进行比较,可以更好地了解数据模型中的更改情况。 你当然知道,因为你做到了,但是现在你看到了所有的变化。 即使那些让你走“像什么?!”的东西。

有一些工具可以为你构建一个模式增量,所以它甚至不是一件难事。 然后你就知道到底会发生什么事情。

应用程序的架构可能会及时演变; 如果您有多个安装(可能是不同的版本),则应该有一些方法来确保您的应用程序,某种工​​具或脚本能够将架构和数据从一个版本逐步迁移到下一个版本。

拥有Hibernate映射(或注释)的所有持久性是控制架构演化的一个非常好的方法。

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

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

  2. 删除旧的专栏,表格和关系

  3. 用默认填充新的列

Hibernate工具对于大多数情况下非常重要(就像我的经验一样),在不同类型的数据库上有不同版本的相同应用程序。

如果你使用Hibernate,Point 3非常敏感,如果你引入一个新的布尔值属性或数字值,如果Hibernate会在这样的列中找到任何空值,如果会引发异常。

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

因此,例如,如果版本更新仅包含添加一个varchar值属性(因此列),可能默认为null,并自动更新,您将完成。 如果需要更多的复杂性,则需要更多的工作。

这是假定更新的应用程序能够更新其架构(可以完成),这也意味着它必须具有在架构上这样做的用户权限。 如果客户的政策阻止了这个(可能是Lizard Brain案例),那么您将不得不提供特定于数据库的脚本。

  • 通常,大型组织中的企业应用程序运行时权限减少

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

我现在正面临这个问题。

我接受了一个项目,在开发中我们不使用自动更新和生产。 说真的,对我来说没有任何意义,因为如果我最后要手动编写sql,那么我们也可以在开发过程中手工完成。

我问了一个比我大的项目开发人员,他指着我这个话题,但是c'mom家伙,如果我们不能在生产中使用自动更新,我也没有看到在开发中使用它的任何理由,因为它seels一种虚假的生产感,但事实上,它提供了一个大问题,我的团队将如何知道你做了什么,你更新了哪些表格,在部署到生产之前我需要做些什么改变。

我的建议是:抢自动更新的手,并在一切使用它,或根本不使用它。