Db migrate - Hibernate / JPA - hbm2ddl - diff工具

时间:2009-07-17 10:13:53

标签: database hibernate ejb-3.0 hbm2ddl liquibase

我用:

  • EJB3 / JPA(Hibernate)
  • MySQL 5

我必须设置一个系统来帮助数据库迁移。试图使用LiquiBase,但似乎还不够成熟,不能与Hibernate一起使用。

我想做的是:

  • 我有生产中的应用程序1.0版
  • 我开发并测试了应用程序的2.0版本
  • 我想在生产中更新应用程序数据库而不会丢失数据

实际上我想使用新的persistence.xml和生产数据库来生成旧数据库和新数据库之间的“delta”。我希望能够检索hbm2ddl处于“更新”模式时执行的SQL代码。

将修改此SQL代码(drop + create = rename etc ...)以避免丢失hbm2ddl.auto=update可能发生的数据。

我想这是可能的,因为Hibernate在使用hbm2ddl.auto=update部署新版本时会这样做。但我希望能够在hibernatetool的Ant任务中执行此操作。

我在互联网上找不到很多关于此的信息,所以我想知道是否有人在这里做了类似的事情并且可以帮助我。

我做了以下事情:

<hibernatetool destdir="${dist}">
            <!--
            <jdbcconfiguration propertyfile="hibtest.properties"></jdbcconfiguration>
            -->
            <jpaconfiguration persistenceunit="server-pu" />
            <classpath>
                <fileset dir="${core.lib.server}" includes="*.jar" />
                <fileset dir="${core.lib.runtime}" includes="*.jar" />
                <fileset dir="${core.lib.build}" includes="*.jar" />
                <pathelement location="${core.class}" />
                <pathelement location="${core.etc}" />
            </classpath>
            <hbm2ddl outputfilename="schema-delta.sql" format="true"
                export="false" update="true" />
</hibernatetool>

我真的不知道该怎么做,我能够获得创建sql文件,但我只想要delta。 我必须把update =“true”? 我可以将jpaconfig与应用程序服务器外部的持久性单元一起使用(数据库设置在Glassfish上的JNDI资源上设置)。 (试过,它只是找不到数据库)

我还尝试使用<jdbcconfiguration propertyfile="hibtest.properties"></jdbcconfiguration>或在persistence.xml中设置数据库的属性,而不是使用JNDI资源。

我收到以下错误:

BUILD FAILED
/home/slorber/workspace/build/build.xml:899: org.hibernate.exception.JDBCConnectionException: Getting database metadata
    at org.hibernate.tool.ant.HibernateToolTask.reportException(HibernateToolTask.java:226)
    at org.hibernate.tool.ant.HibernateToolTask.execute(HibernateToolTask.java:189)
    at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:288)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:105)
    at org.apache.tools.ant.Task.perform(Task.java:348)
    at org.apache.tools.ant.Target.execute(Target.java:357)
    at org.apache.tools.ant.Target.performTasks(Target.java:385)
    at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1329)
    at org.apache.tools.ant.Project.executeTarget(Project.java:1298)
    at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
    at org.eclipse.ant.internal.ui.antsupport.EclipseDefaultExecutor.executeTargets(EclipseDefaultExecutor.java:32)
    at org.apache.tools.ant.Project.executeTargets(Project.java:1181)
    at org.eclipse.ant.internal.ui.antsupport.InternalAntRunner.run(InternalAntRunner.java:423)
    at org.eclipse.ant.internal.ui.antsupport.InternalAntRunner.main(InternalAntRunner.java:137)
Caused by: org.hibernate.exception.JDBCConnectionException: Getting database metadata
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:97)
    at org.hibernate.cfg.reveng.dialect.AbstractMetaDataDialect.getMetaData(AbstractMetaDataDialect.java:64)
    at org.hibernate.cfg.reveng.dialect.AbstractMetaDataDialect.caseForSearch(AbstractMetaDataDialect.java:163)
    at org.hibernate.cfg.reveng.dialect.JDBCMetaDataDialect.getTables(JDBCMetaDataDialect.java:22)
    at org.hibernate.cfg.reveng.JDBCReader.processTables(JDBCReader.java:476)
    at org.hibernate.cfg.reveng.JDBCReader.readDatabaseSchema(JDBCReader.java:74)
    at org.hibernate.cfg.reveng.JDBCReader.readDatabaseSchema(JDBCReader.java:860)
    at org.hibernate.cfg.JDBCBinder.readDatabaseSchema(JDBCBinder.java:115)
    at org.hibernate.cfg.JDBCBinder.readFromDatabase(JDBCBinder.java:88)
    at org.hibernate.cfg.JDBCMetaDataConfiguration.readFromJDBC(JDBCMetaDataConfiguration.java:42)
    at org.hibernate.tool.ant.JDBCConfigurationTask.doConfiguration(JDBCConfigurationTask.java:81)
    at org.hibernate.tool.ant.ConfigurationTask.getConfiguration(ConfigurationTask.java:55)
    at org.hibernate.tool.ant.HibernateToolTask.getConfiguration(HibernateToolTask.java:302)
    at org.hibernate.tool.ant.Hbm2DDLExporterTask.createExporter(Hbm2DDLExporterTask.java:51)
    at org.hibernate.tool.ant.ExporterTask.execute(ExporterTask.java:39)
    at org.hibernate.tool.ant.HibernateToolTask.execute(HibernateToolTask.java:186)
    ... 15 more
Caused by: java.sql.SQLException: No suitable driver found for jdbc:mysql:3306//localhost/db
    at java.sql.DriverManager.getConnection(DriverManager.java:602)
    at java.sql.DriverManager.getConnection(DriverManager.java:154)
    at org.hibernate.connection.DriverManagerConnectionProvider.getConnection(DriverManagerConnectionProvider.java:133)
    at org.hibernate.cfg.reveng.dialect.AbstractMetaDataDialect.getConnection(AbstractMetaDataDialect.java:122)
    at org.hibernate.cfg.reveng.dialect.AbstractMetaDataDialect.getMetaData(AbstractMetaDataDialect.java:61)
    ... 29 more
--- Nested Exception ---
org.hibernate.exception.JDBCConnectionException: Getting database metadata
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:97)
    at org.hibernate.cfg.reveng.dialect.AbstractMetaDataDialect.getMetaData(AbstractMetaDataDialect.java:64)
    at org.hibernate.cfg.reveng.dialect.AbstractMetaDataDialect.caseForSearch(AbstractMetaDataDialect.java:163)
    at org.hibernate.cfg.reveng.dialect.JDBCMetaDataDialect.getTables(JDBCMetaDataDialect.java:22)
    at org.hibernate.cfg.reveng.JDBCReader.processTables(JDBCReader.java:476)
    at org.hibernate.cfg.reveng.JDBCReader.readDatabaseSchema(JDBCReader.java:74)
    at org.hibernate.cfg.reveng.JDBCReader.readDatabaseSchema(JDBCReader.java:860)
    at org.hibernate.cfg.JDBCBinder.readDatabaseSchema(JDBCBinder.java:115)
    at org.hibernate.cfg.JDBCBinder.readFromDatabase(JDBCBinder.java:88)
    at org.hibernate.cfg.JDBCMetaDataConfiguration.readFromJDBC(JDBCMetaDataConfiguration.java:42)
    at org.hibernate.tool.ant.JDBCConfigurationTask.doConfiguration(JDBCConfigurationTask.java:81)
    at org.hibernate.tool.ant.ConfigurationTask.getConfiguration(ConfigurationTask.java:55)
    at org.hibernate.tool.ant.HibernateToolTask.getConfiguration(HibernateToolTask.java:302)
    at org.hibernate.tool.ant.Hbm2DDLExporterTask.createExporter(Hbm2DDLExporterTask.java:51)
    at org.hibernate.tool.ant.ExporterTask.execute(ExporterTask.java:39)
    at org.hibernate.tool.ant.HibernateToolTask.execute(HibernateToolTask.java:186)
    at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:288)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:105)
    at org.apache.tools.ant.Task.perform(Task.java:348)
    at org.apache.tools.ant.Target.execute(Target.java:357)
    at org.apache.tools.ant.Target.performTasks(Target.java:385)
    at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1329)
    at org.apache.tools.ant.Project.executeTarget(Project.java:1298)
    at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
    at org.eclipse.ant.internal.ui.antsupport.EclipseDefaultExecutor.executeTargets(EclipseDefaultExecutor.java:32)
    at org.apache.tools.ant.Project.executeTargets(Project.java:1181)
    at org.eclipse.ant.internal.ui.antsupport.InternalAntRunner.run(InternalAntRunner.java:423)
    at org.eclipse.ant.internal.ui.antsupport.InternalAntRunner.main(InternalAntRunner.java:137)
Caused by: java.sql.SQLException: No suitable driver found for jdbc:mysql:3306//localhost/db
    at java.sql.DriverManager.getConnection(DriverManager.java:602)
    at java.sql.DriverManager.getConnection(DriverManager.java:154)
    at org.hibernate.connection.DriverManagerConnectionProvider.getConnection(DriverManagerConnectionProvider.java:133)
    at org.hibernate.cfg.reveng.dialect.AbstractMetaDataDialect.getConnection(AbstractMetaDataDialect.java:122)
    at org.hibernate.cfg.reveng.dialect.AbstractMetaDataDialect.getMetaData(AbstractMetaDataDialect.java:61)
    ... 29 more

我使用MySQL,我的JDBC属性是:

hibernate.dialect=org.hibernate.dialect.MySQLInnoDBDialect
hibernate.connection.driver_class=com.mysql.jdbc.Driver
hibernate.connection.url=jdbc:mysql:3306//localhost/db
hibernate.connection.username=root
hibernate.connection.password=root
hibernate.connection.show_sql=true

我的JDBC MySQL驱动程序位于${core.lib.server}: mysql-connector-java-5.1.7-bin.jar。 (我也尝试放入类路径<fileset dir="/home/slorber/workspace/core/lib/server" includes="*.jar" />。)

我还将它添加到Ant(Eclipse插件)的运行配置类路径中。

所以我的问题是:

  • 我做错了什么来做我想做的事?
  • 这是您使用Hibernate框架进行数据库迁移的方式吗? (如果不在手工制作的SQL文件中编写所有数据库更改,还会做什么?)

1 个答案:

答案 0 :(得分:2)

Hbm2ddl确实有一个你可以自己调用的API。如果现有的ant任务没有按你的意愿执行,你总是可以自己调用hbm2ddl,甚至可以通过hibernate传递一个重载的jdbc驱动程序来记录执行语句,而不是实际执行它们或重载hbm2ddl执行方法。

我还想补充一点,你应该看一下使用liquibase并在任何类型的差异上手动创建xml文件。您认识到需要验证生成的sql是否正确,在开发过程中一次创建一步就很容易,然后您就知道它是正确的。

我们使用hibernate,而不是使用liquibase hibernate集成,我们更新我们的hibernate映射,运行我们的集成测试以查看它们是否失败,创建必要的liquibase变更集(添加表,添加列,重命名列等) ,然后重新运行测试并看到它们通过。逐步构建更改日志与常规的开发节奏相得益彰,而不需要在超出完整性检查的范围内进行差异化处理。