Миграция базы данных — Hibernate/JPA — hbm2ddl — инструменты сравнения

Я использую:

  • EJB3/JPA (спящий режим)
  • MySQL 5

Мне нужно настроить систему, чтобы помочь миграции базы данных. Пытался использовать LiquiBase, но он кажется недостаточно зрелым для использования с Hibernate.

Что я хотел бы сделать, так это:

  • У меня версия 1.0 приложения в производстве
  • У меня разработана и протестирована версия 2.0 приложения
  • Я хочу обновить базу данных приложения в рабочей среде без потери данных

На самом деле я хотел бы использовать новую persistence.xml и производственную базу данных, чтобы иметь возможность генерировать «дельту» между старой базой данных и новой. Я хотел бы получить код SQL, который выполняется, когда hbm2ddl находится в режиме «обновления».

Этот код SQL будет изменен (удалить+создать=переименовать и т. д.), чтобы избежать потери данных, которая может произойти с hbm2ddl.auto=update.

Я думаю, это возможно, потому что Hibernate делает это при развертывании новой версии с hbm2ddl.auto=update. Но я хочу иметь возможность сделать это в задаче Ant с помощью hibernatetool.

Я не нахожу много информации об этом в Интернете, поэтому мне интересно, сделал ли кто-нибудь что-то подобное здесь и мог бы мне помочь.

Я сделал следующее:

<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, но мне просто нужна дельта. Я должен поставить update="true" ? Могу ли я использовать jpaconfig с блоком сохраняемости за пределами сервера приложений (настройки базы данных установлены на ресурсе JNDI на Glassfish). (пробовал и просто не может найти БД)

Я также пробовал с <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, сделанные вручную?)

person Sebastien Lorber    schedule 17.07.2009    source источник
comment
забавно, одна из моих самых читаемых тем, а не +1 :D   -  person Sebastien Lorber    schedule 17.11.2011


Ответы (1)


У Hbm2ddl есть API, который вы можете вызывать самостоятельно. Если существующие задачи ant не делают то, что вам нужно, вы всегда можете сами вызвать hbm2ddl, возможно, даже передав hibernate перегруженный драйвер jdbc, который регистрирует операторы выполнения, а не выполняет их на самом деле или перегружает методы выполнения hbm2ddl.

Я бы также добавил, что вам следует взглянуть на использование liquibase и создание файлов xml вручную для любых различий. Вы понимаете, что вам нужно будет проверить правильность сгенерированного sql, так же легко создать его шаг за шагом, как вы разрабатываете, и тогда вы ЗНАЕТЕ, что это правильно.

Мы используем спящий режим, и вместо использования интеграции с гибернацией liquibase мы обновляем наши сопоставления спящего режима, запускаем наши интеграционные тесты, чтобы убедиться, что они не работают, создаем необходимый набор изменений liquibase (добавить таблицу, добавить столбец, переименовать столбец и т. д.), а затем повторно -запустите тесты и посмотрите, как они проходят. Пошаговое создание журналов изменений хорошо работает в обычном ритме разработки, не прибегая к различиям для чего-либо, кроме проверки работоспособности.

person Nathan Voxland    schedule 18.07.2009