是否可以运行配置了hbm2ddl的Hibernate应用程序。自动=update在生产环境中更新数据库模式?
不,不安全。
尽管Hibernate团队尽了最大努力,但在生产环境中不能依赖自动更新。编写您自己的补丁,与DBA一起检查它们,测试它们,然后手动应用它们。
从理论上讲,如果hbm2ddl更新在开发中有效,那么它在生产中也应该有效。但在现实中,情况并非总是如此。
即使它运行正常,也可能不是最优的。dba的薪水这么高是有原因的。
我们在生产环境中进行,尽管应用程序不是关键任务,也没有高薪的dba。这只是减少了一个受人为错误影响的手动过程——应用程序可以检测到差异并做正确的事情,而且您可能已经在各种开发和测试环境中对其进行了测试。
一个警告——在集群环境中,你可能想要避免它,因为多个应用程序可能会同时出现,并试图修改模式,这可能是不好的。或者放入某种只允许一个实例更新模式的机制。
我同意弗拉基米尔的观点。如果我提出这样的课程,我公司的管理人员肯定不会感激。
此外,创建SQL脚本而不是盲目地信任Hibernate,使您有机会删除不再使用的字段。Hibernate不会这样做。
我发现,比较生产模式和新模式可以让您更好地了解数据模型中所更改的内容。当然,你知道,因为你成功了,但现在你看到所有的变化一气呵成。即使是那些让你想“搞什么鬼?!”
有一些工具可以为您创建模式增量,因此这甚至不是一项艰巨的工作。然后你就知道会发生什么了。
我会投反对票。当列的数据类型发生变化时,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以上,然后看到它转换为文本、mediumtext等等。
当然,我不认为真的有一种方法可以在不创建新列、复制数据和删除旧列的情况下“转换数据类型”。但是一旦你的数据库中有不能反映当前Hibernate映射的列,你就非常危险了……
Flyway是解决这个问题的一个很好的选择:
http://flywaydb.org
应用程序的模式可能会随着时间而变化;如果您有多个安装,可能是不同的版本,您应该有某种方法来确保您的应用程序、某种工具或脚本能够逐步将模式和数据从一个版本迁移到下一个版本。
将所有持久性放在Hibernate映射(或注释)中是控制模式演变的一种非常好的方法。
您应该考虑模式演化有几个方面需要考虑:
数据库模式的演变 添加更多的列和表 删除旧的列,表和 关系 用默认值填充新列
Hibernate工具非常重要,特别是当你在许多不同类型的数据库上有相同应用程序的不同版本时(就像我的经验一样)。
第3点在使用Hibernate时非常敏感,例如在引入一个新的布尔值属性或数值属性时,如果Hibernate在这些列中发现任何空值,则会引发异常。
所以我要做的是:确实使用Hibernate工具的模式更新功能,但必须在它旁边添加一些数据和模式维护回调,比如填充默认值,删除不再使用的列,等等。通过这种方式,您获得了优势(独立于数据库的模式更新脚本和避免在持久性和脚本中对更新进行重复编码),但也涵盖了操作的所有方面。
因此,例如,如果版本更新只是添加一个varchar值属性(即列),它可能默认为null,那么使用自动更新就可以完成。在需要更复杂的地方,就需要做更多的工作。
这是假设更新时的应用程序能够更新其模式(这是可以做到的),这也意味着它必须拥有对模式进行更新的用户权限。如果客户的策略阻止了这一点(可能是Lizard Brain的情况),您将不得不提供特定于数据库的脚本。
Hibernate创建者在他们的书“Java Persistence with Hibernate”中不鼓励在生产环境中这样做:
警告:我们已经看到Hibernate用户试图使用SchemaUpdate自动更新生产数据库的模式。这很快就会导致灾难,而且DBA不允许这样做。
我们在一个已经在生产环境中运行了几个月的项目中这样做,到目前为止从来没有遇到过问题。记住这道菜需要的两种原料:
Design your object model with a backwards-compatibility approach, that is deprecate objects and attributes rather than removing/altering them. This means that if you need to change the name of an object or attribute, leave the old one as is, add the new one and write some kind of migration script. If you need to change an association between objects, if you already are in production, this means that your design was wrong in the first place, so try to think of a new way of expressing the new relationship, without affecting old data. Always backup the database prior to deployment.
我的感觉是——在阅读了这篇文章之后——参与讨论的90%的人一想到在生产环境中使用这样的自动化就感到恐惧。有些人把球扔向DBA。花点时间考虑一下,并不是所有的生产环境都会提供DBA,也不是很多开发团队能够负担得起(至少对于中等规模的项目)。所以,如果我们谈论的是每个人都必须做所有事情的团队,球就在他们身上。
既然如此,为什么不试着两全其美呢?像这样的工具可以提供帮助,通过仔细的设计和计划,可以在许多情况下提供帮助。相信我,最初可能很难说服管理人员,但如果他们知道球不在他们手中,他们就会喜欢它。
就我个人而言,我永远不会回到手工编写脚本来扩展任何类型的模式,但这只是我的观点。在最近开始采用NoSQL无模式数据库之后,我可以看到,不久之后,所有这些基于模式的操作都将成为过去,所以你最好开始改变你的观点,展望未来。
查看LiquiBase XML以保持更新的更新日志。直到今年我才开始使用它,但我发现它非常容易学习,并且使DB修订控制/迁移/变更管理非常简单。我在一个Groovy/Grails项目中工作,Grails在其所有ORM(称为“GORM”)的底层使用Hibernate。我们使用Liquibase来管理所有SQL模式的更改,随着应用程序的新功能的发展,我们经常这样做。
Basically, you keep an XML file of changesets that you continue to add to as your application evolves. This file is kept in git (or whatever you are using) with the rest of your project. When your app is deployed, Liquibase checks it's changelog table in the DB you are connecting to so it will know what has already been applied, then it intelligently just applies whatever changesets have not been applied yet from the file. It works absolutely great in practice, and if you use it for all your schema changes, then you can be 100% confident that code you checkout and deploy will always be able to connect to a fully compatible database schema.
最棒的是,我可以在我的笔记本电脑上使用一个完全空白的mysql数据库,启动应用程序,模式就马上为我设置好了。通过首先将模式更改应用到本地开发或登台db,还可以很容易地测试模式更改。
开始使用它的最简单方法可能是使用现有的DB,然后使用Liquibase生成一个初始的baseline.xml文件。然后在将来,您可以添加到它,并让liquibase接管管理模式更改。
http://www.liquibase.org/
Hibernate必须在prod中声明不使用自动更新,以在不应该使用prod的情况下,当不知道自己在做什么的人使用它时,Hibernate可以保护自己。
当然,不应该使用的情况远远超过可以使用的情况。
我已经在许多不同的项目中使用它很多年了,从来没有出现过一个问题。这不是一个蹩脚的答案,也不是牛仔编码。这是历史事实。
一个人说“永远不要在生产中这样做”,他想到的是一组特定的生产部署,即他所熟悉的(他的公司,他的行业等)。
“生产部署”的范围是巨大而多样的。
有经验的Hibernate开发人员确切地知道给定映射配置将产生什么DDL。只要您测试并验证您期望的内容最终出现在DDL中(在开发、qa、登台等),就没问题。
在添加大量特性时,自动模式更新可以真正节省时间。
自动更新不能处理的事情是无穷无尽的,但一些例子是数据迁移,添加非空列,列名更改,等等。
此外,您还需要注意集群环境。
但话说回来,如果你知道这些,你就不会问这个问题了。嗯……好的,如果您正在问这个问题,那么在考虑在prod中使用它之前,您应该等到对Hibernate和自动模式更新有了丰富的经验。
在我的情况下(Hibernate 3.5.2, Postgresql, Ubuntu),设置Hibernate .hbm2ddl。Auto =update仅创建新表,并在已有的表中创建新列。 它既不删除表,也不删除列,也不更改列。它可以被称为一个安全的选择,但有点像hibernate.hbm2ddl。Auto =create_tables add_columns更清楚。
这不安全,也不推荐,但这是可能的。
我有在生产环境中使用自动更新选项的应用程序的经验。
在这个解决方案中发现的主要问题和风险是:
Deploy in the wrong database. If you commit the mistake to run the application server with a old version of the application (EAR/WAR/etc) in the wrong database... You will have a lot of new columns, tables, foreign keys and errors. The same problem can occur with a simple mistake in the datasource file, (copy/paste file and forgot to change the database). In resume, the situation can be a disaster in your database. Application server takes too long to start. This occur because the Hibernate try to find all created tables/columns/etc every time you start the application. He needs to know what (table, column, etc) needs to be created. This problem will only gets worse as the database tables grows up. Database tools it's almost impossible to use. To create database DDL or DML scripts to run with a new version, you need to think about what will be created by the auto-update after you start the application server. Per example, If you need to fill a new column with some data, you need to start the application server, wait to Hibernate crete the new column and run the SQL script only after that. As can you see, database migration tools (like Flyway, Liquibase, etc) it's almost impossible to use with auto-update enabled. Database changes is not centralized. With the possibility of the Hibernate create tables and everything else, it's hard to watch the changes on database in each version of the application, because most of them are made automatically. Encourages garbage on database. Because of the "easy" use of auto-update, there is a chance your team neglecting to drop old columns and old tables, because the hibernate auto-update can't do that. Imminent disaster. The imminent risk of some disaster to occur in production (like some people mentioned in other answers). Even with an application running and being updated for years, I don't think it's a safe choice. I never felt safe with this option being used.
因此,我不建议在生产环境中使用自动更新。
如果你真的想在生产环境中使用自动更新,我建议:
网络分开。您的测试环境无法访问同源环境。这有助于防止原本应该在测试环境中的部署更改同源数据库。 管理脚本顺序。您需要在部署之前(结构表更改、删除表/列)和部署之后(填充新列/表的信息)组织运行的脚本。
而且,与其他文章不同的是,我不认为自动更新启用了它与“高薪”dba有关(如其他文章所述)。dba有比编写SQL语句来创建/更改/删除表和列更重要的事情要做。这些简单的日常任务可以由开发人员完成和自动化,只需要DBA团队进行检查,而不需要Hibernate和DBA“高薪”编写它们。
使用hbm2ddl不是一个好主意。汽车生产。
管理数据库模式的唯一方法是使用增量迁移脚本,因为:
脚本将与你的代码库一起驻留在VCS中。签出分支时,从头重新创建整个模式。 增量脚本在应用到生产环境之前可以在QA服务器上进行测试 不需要手动干预,因为脚本可以通过Flyway运行,因此它减少了与手动运行脚本相关的人为错误的可能性。
甚至Hibernate用户指南也建议您避免在生产环境中使用hbm2ddl工具。
推荐文章
- 如何分割逗号分隔的字符串?
- Java字符串—查看字符串是否只包含数字而不包含字母
- Mockito.any()传递带有泛型的接口
- 在IntelliJ 10.5中运行测试时,出现“NoSuchMethodError: org.hamcrest. matcher . descripbemismatch”
- 使用String.split()和多个分隔符
- Java数组有最大大小吗?
- 在Android中将字符串转换为Uri
- 从JSON生成Java类?
- 为什么java.util.Set没有get(int index)?
- Swing和AWT的区别是什么?
- 为什么Java流是一次性的?
- 四舍五入BigDecimal *总是*有两位小数点后
- 设计模式:工厂vs工厂方法vs抽象工厂
- Java:检查enum是否包含给定的字符串?
- 它的意思是:序列化类没有声明一个静态的最终serialVersionUID字段?