10

I have a Java EE web application (hibernate3, seam) that I'm using in Weblogic container. I want to introduce Liquibase for schema migrations. Currently we use

<property name="hibernate.hbm2ddl.auto" value="update"/>

which we want to drop because it can be dangerous.

I want the migration to automatically happen at deployments, so I'm using the servlet listener integration.

In web.xml, the first listener is:

<listener>
    <listener-class>liquibase.integration.servlet.LiquibaseServletListener</listener-class>
</listener>

Sadly, this listener comes into play after the Hibernate initialization and it throws missing table errors (because the schema is empty). I'm google-ing like a boss for hours and I'm a bit confused now.

Thanks in advance

UPDATE

If I set <property name="hibernate.hbm2ddl.auto" value="none" />, liquibase finishes it's job successfully and the app starts up as expected. If I set validate, it seems like hibernate schema validation takes place before liquibase and it cries because of missing tables.

UPDATE

It seems like Seam initializes Hibernate, but Liquibase listener is listed before SeamListener, so I have no clue on how to enable schema validation and liquibase at the same time...

gyorgyabraham
  • 2,550
  • 1
  • 28
  • 46
  • How is your hibernate set up? There are also `pre-update` events that you can assign a listener to. Maybe this will help: https://forum.hibernate.org/viewtopic.php?f=1&t=994777 – Display Name is missing Nov 06 '13 at 17:54
  • @better_use_mkstemp I'm somewhat a beginner at the EE applications. This webapp uses Seam 2.2 and Hibernate 3.x. I have 3 listeners in web.xml: LiquibaseServletListener, com.sun.faces.config.ConfigureListener and org.jboss.seam.servlet.SeamListener. I have a persistence.xml too. There are no other hibernate-related configs. – gyorgyabraham Nov 07 '13 at 09:28
  • Have you tried to put `LiquibaseServletListener` before `ConfigureListener` and `SeamListener` in `web.xml`. They should be called in exactly same order. – Milan Baran Nov 13 '13 at 13:46
  • @MilanBaran Yes, as I wrote "In web.xml, the first listener is" – gyorgyabraham Nov 13 '13 at 14:12
  • So, you are using same persistence profile for both Liquibase and application, right? You should separate them. – Milan Baran Nov 13 '13 at 15:44

2 Answers2

1

My understanding is that the LiquibaseServletListener requires the path to change log file which is passed using liquibase.changelog context param. So you already have a change log generated or am I missing something here ?

You can take a look at the liquibase hibernate integration library provided by Liquibase. This library works with both the classic hibernate configuration (via .cfg and .xml files) as well as JPA configuration via persistence.xml.

AFAIK, generating the changelog and running the change log are two seperate process. Liquibase hibernate integration library helps in generating the change log from the diff of current state of entities in persistence unit and the current database state.

Shailendra
  • 8,874
  • 2
  • 28
  • 37
  • Thanks for the answer! I already have the changelog (and this part works very well if i completely disable hbm2ddl). I want the developer to write it as time passes by hand and keep the hibernate validation at the end to check the schema - entities consistency. – gyorgyabraham Nov 14 '13 at 13:42
  • So then your issue boils down to the order in which the listeners are run – Shailendra Nov 14 '13 at 13:50
  • Yes. And the weird thing is, the declaration order is correct in web.xml. I guess the seam (listener) hacks around something in the background, because it handles hibernate. – gyorgyabraham Nov 14 '13 at 14:10
  • You can try to check in the server logs if the listeners are being called in the expected order – Shailendra Nov 14 '13 at 14:10
  • Just to double check you can create your own very simple ServletContextListener which simply outputs some string on context initialization and place it at different order to see the behaviour – Shailendra Nov 14 '13 at 14:18
  • Thanks, these are very valuable tips! – gyorgyabraham Nov 14 '13 at 14:24
1

How to determine the order of listeners in web.xml

You should place:

<listener>
    <listener-class>liquibase.integration.servlet.LiquibaseServletListener</listener-class>
</listener>

before ORM or framework other related listeners.

I use Spring beans LiquiBase activation to reduce DB authentication data duplication by using already provided datasource bean:

<bean id="liquibase" class="liquibase.integration.spring.SpringLiquibase">
    <property name="dataSource" ref="dataSource" />
    <property name="changeLog" value="classpath:sql/master.sql" />
    <property name="defaultSchema" value="PRODUCT" />
</bean>

To restrict order use depends-on attribute:

<bean id="entityManagerFactory"
      class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
      depends-on="liquibase">
    <property name="dataSource" ref="dataSource" />
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
    </property>
    <property name="packagesToScan" value="product.domain" />
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
            <prop key="hibernate.hbm2ddl.auto">validate</prop>
        </props>
    </property>
</bean>
Community
  • 1
  • 1
gavenkoa
  • 45,285
  • 19
  • 251
  • 303
  • 1
    I used similar approach for flyway and hibernate validate. It worked for me too! And now I just wanted to do the same for liquibase, so this answer helped me to recall this. thanks. – Yan Khonski Jan 09 '17 at 13:41