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...
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.
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>
Related
I am trying to configure a test for hibernate 4.3 with JPA and Spring 4 using the following config:
<bean id="em" class="LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="persistenceXmlLocation"
value="classpath:integrations/hibernate4/jpa/persistence.xml" />
</bean>
Now the persistence config looks as follows:
<persistence-unit name="test" >
<class>hibernate4.jpa.JpaEntity</class>
<class>hibernate4.jpa.JpaHiLoEntity</class>
<properties>
<property name="hibernate.hbm2ddl.auto" value="create" />
</properties>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
</persistence-unit>
If I run the above with hibernate 4.2.4 everything runs fine, however with 4.3 the above setup loads ALL hbm.xml resource files, some of which refer to classes that are not present on the classpath, causing ClassNotFoundException.
Does anyone know what the reason for the changed behavior is and how to stop hibernate from scanning for hbm.xml files (packagesToScan property did not work either)?
I ran into this problem as well. The hibernate.archive.autodetection property controls what Hibernate will automatically scan for:
If the property is undefined, hbm files will be included, and annotated classes will be included unless <exclude-unlisted-classes> is set to true.
If the value of the property contains "hbm" then .hbm.xml files will be included. Otherwise they won't be.
If the value contains "class", then any annotated classes on the classpath will be included. Otherwise they won't be.
If the property is defined at all, regardless of its value, it affects the behavior of Hibernate. See the org.hibernate.jpa.boot.scan.internal.StandardScanOptions constructor.
For my purposes, I needed the persistence unit to include only the entities that were explicitly listed in <class> elements. To accomplish this, I defined the property with a value of "none":
<persistence-unit name="num2" transaction-type="RESOURCE_LOCAL">
...
<properties>
...
<property name="hibernate.archive.autodetection" value="none" />
</properties>
</persistence-unit>
Unfortunately, the only documentation I could find on this property was for the stable release, whatever that is. There was no mention of it in the docs for Hibernate 4.3, but that is the version I use and I can confirm the property works.
Also you can also configure the bean em without using the file persistence.xml. e.g.:
<bean id="em"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSource"
p:packagesToScan="ยทยทยท.model">
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
p:showSql="false"
p:databasePlatform="org.hibernate.dialect.SQLServerDialect" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
</bean>
The exclude-unlisted-classes doesn't work if your class is in the packages to scan, e.g. you want to have it registered, but doesn't want the hbm.xml for it.
I fixed that using hibernate property hibernate.archive.autodetection set to class, making Hibernate scan only classes and not mapping files.
<properties>
<property name="hibernate.archive.autodetection" value="class" />
</properties
I was wondering if it is possible to use two transaction manager in one service methods.
Because due to the limitation of client's mysql db configuration, we have got 2 different datasources within one database, i.e., one user/pwd/url per schema. Thats why i have to configured two transaction managers. Now I got problem when it comes to the service implementation. See the following code:
public class DemoService{
...
#Transactional(value = "t1")
public doOne(){
doTwo();
}
#Transactional(value = "t2")
public doTwo(){
}
...
}
if I using this code pattern, i always got the exception
org.hibernate.HibernateException: No Session found for current thread
If i run the two methods seperately, it workd fine.
Did i miss something? Or there is other work around here?
Any advice would be appreciated.
btw: some of my configuration
<bean id="sessionFactorySso" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="mappingLocations">
<list>
<value>classpath*:sso.vo/*.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">true</prop>
<prop key="generateDdl">true</prop>
<prop key="hibernate.dialect">${dialect} </prop>
</props>
</property>
<property name="dataSource" ref="dataSourceSso"/>
</bean>
<bean id="dataSourceSso" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${driver}"/>
<property name="jdbcUrl" value="${sso.url}"/>
<property name="user" value="${sso.username}"/>
<property name="password" value="${sso.password}"/>
<!-- these are C3P0 properties -->
<property name="acquireIncrement" value="2" />
<property name="minPoolSize" value="1" />
<property name="maxPoolSize" value="2" />
<property name="automaticTestTable" value="test_c3p0" />
<property name="idleConnectionTestPeriod" value="300" />
<property name="testConnectionOnCheckin" value="true" />
<property name="testConnectionOnCheckout" value="true" />
<property name="autoCommitOnClose" value="true" />
<property name="checkoutTimeout" value="1000" />
<property name="breakAfterAcquireFailure" value="false" />
<property name="maxIdleTime" value="0" />
</bean>
<bean id="transactionManagerSso" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactorySso"/>
<qualifier value="sso" />
</bean>
<tx:annotation-driven transaction-manager="transactionManagerSso" />
Because you want to enlist two data sources in one transaction you need XA(Global) Transaction.
Therefore you need to:
Set the Spring JTA transaction manager
You Hibernate properties should use the JTA platform settings
Your data source connections should be XA complaint
You need an application server JTA transaction manager or a stand-alone tarnsaction manager (Bitronix, Atomikos, JOTM)
You will need two session factory configurations, one for each individual data source.
And you won't have two transaction managers: t1 and t2, but instead you will enlist two transactional XA data sources that will be automatically enlisted in the same global transaction, meaning you will have two XA connections being enlisted in the same global transaction. The XA transaction will use the 2PC protocol to commit both resources upon commit time.
Checkout this Bitronix Hibernate example.
You have a few options:
Inject the bean into itself and use the reference to call doTwo(). This really goes against the whole idea of IoC and AOP so I don't recommend it.
Switch to compile time weaving. Rather than using proxies, Spring (actually the AspectJ compiler) will add the bytecode to start/stop transactions to your class at compile time. There are pros and cons to this approach. See this page for more details.
Use load time weaving. Same as #2 except that your classes are modified as they are loaded rather than at compile time. IMO, Java classloading is complicated enough. I'm sure this works great for some folks but I personally would avoid this.
As Vlad pointed out, you can use JTA and XA.
Start a new transaction against transaction manager 2 within doOne() before calling doTwo(). RTFM on programmatic transaction management.
Check out ChainedTransactionManager. It essentially aggregates multiple transaction managers and does a "best effort" with commit/rollback. This is NOT a true two-phase commit like Vlad's solution.
All of these except for Vlad's solution (#4) have the potential to leave the databases in an inconsistent state. You need to use JTA/XA/two-phase commit to ensure consistency in the event that one of the TX managers throws an exception at commit time.
Currently i am using spring 2.5 XML based configuration for bean. Now i want to upgrade it to Spring 3.x. I want to know after upgrading to 3.x my old XML configuration will work or not. If works then can i write annotation based configuration for new work in my current project.
Example of XML configuration:
<bean id="addTestimonialController" class="com.eam.web.testimonial.AddTestimonialController" singleton="true">
<property name="branchManager" ref="branchMan"/>
<property name="userManager" ref="userMan"/>
<property name="itemManager" ref="itemMan"/>
<property name="vendorManager" ref="vendorMan"/>
<property name="categoryManager" ref="categoryMan"/>
<property name="lineupManager" ref="lineupMan"/>
<property name="testimonialManager" ref="testimonialMan"/>
<property name="categoryMenuManager" ref="categoryMenuMan"/>
<property name="setManager" ref="setMan"/>
<property name="configurationManager" ref="configMan"/>
<property name="cartManager" ref="cartMan"/>
<property name="employeeManager" ref="employeeMan"/>
<property name="employeeBranchManager" ref="employeeBranchMan"/>
<property name="orderItemManager" ref="orderItemMan"/>
<property name="orderFaxManager" ref="orderFaxMan"/>
<property name="sessionForm" value="true"/>
<property name="commandName" value="addTestimonialBean"/>
<property name="branchesVendorManager" ref="branchesVendorMan" />
<property name="commandClass" value="com.eam.bus.testimonial.TestimonialBean"/>
<property name="validator" ref="addTestimonialValidator"/>
<property name="formView" value="addtestimonial"/>
<property name="successView" value="listtestimonials.html"/>
</bean>
Please help me. Also let me know if you similar link where somebody has explained both the configuration in a single configuration file.
Appreciate your help.
You can very well use both XML based metadata and Annotation based configuration metadata in your application. The configuration metadata is the information how you tell the Spring container to instantiate, configure, and assemble the objects in your application. Configuration metadata is traditionally supplied in a simple and intuitive XML format. i.e XML based configuration metadata. Spring 2.5 introduced support for annotation-based configuration metadata.Starting with Spring 3.0, many features provided by the Spring JavaConfig project became part of the core Spring Framework. Thus, you have different ways of providing your configuration metadata of your application through XML, Annotation based and Java config from Spring 3.x versions. This link will take you in the right direction. You must have to learn IOC chapter in Spring documentation
you can use both annotation based configuration and xml based (ControllerClassNameHandlerMapping ) by specifying the order of these handlers.
for annotation based Configuration use below
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" >
<property name="order" value="0"/>
</bean>
for annotation based configuration we have to provide location ie: where to locate annotated controllers.
<context:component-scan base-package="ur packageName" />
here package name will be the package where #Controller classes are located.
for Controller Class Name based url Mapping
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" >
<property name= "order" value="2"/>
</bean>
I've been researching this a bunch today and I'm starting to think that what I want to do may not be possible, so I am turning to you, o mighty Stackoverflow, for help.
I'm building a RESTful services platform in Java, with Spring Data 3.1.2 + JPA as my persistence layer (as documented here). My data model objects are all implemented as interfaces that extend the Spring JpaRepository interface. I've got everything wired up and working nicely with a single datasource, as shown in this example (note that the datasource shown is Derby, but that's just for development purposes; in production, we'll be using Oracle):
<jpa:repositories base-package="com.my.cool.package.repository"/>
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
<property name="packagesToScan" value="com.my.cool.package" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
</bean>
<bean name="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver" />
<property name="url" value="jdbc:derby:derbyDB" />
<property name="username" value="dev" />
<property name="password" value="notARealPassword" />
</bean>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.DerbyTenSevenDialect" />
</bean>
The problem is that this application will need to connect to several (Oracle) databases. The credentials included with each incoming request will contain a field that tells the application which database to go to in order to fulfill that request. The schemas for each database are the same, so there's no need for separate repository interfaces for each database.
After a fair amount of Googling, it's clear that this is a common scenario. To wit:
multiple databases with Spring Data JPA
Spring + Hibernate + JPA + multiple databases
how to setup spring data jpa with multiple datasources
And here's a blog post by a (former?) Spring developer, which isn't actually relevant to the topic at hand, but someone brings it up in the comments, and the author responds with some info:
http://blog.springsource.org/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/#comment-198835
The theme that seems to be emerging is that the way to solve this problem is to define multiple EntityManagerFactories, and to wire each one to the appropriate repositories like so:
<jpa:repositories base-package="com.my.cool.package.repository1" entity-manager-factory-ref="firstEntityManagerFactory" />
<jpa:repositories base-package="com.my.cool.package.repository2" entity-manager-factory-ref="secondEntityManagerFactory" />
However, as I've mentioned, I want to reuse my repository across all of the datasources, so this approach doesn't seem like it would work.
I know that there's no way around having logic in my code that takes the relevant piece of information from the request, and uses it to determine which datasource (or EntityManagerFactory) to use. The part I'm struggling with is how to get a handle to that datasource/EntityManagerFactory and "inject" it into my repository objects. Any ideas?
If you're really using the different DataSourcees in a multi-tenant kind of way (essentially assigning a request to a DataSource and sticking with it for the entire request) you should have a look at AbstractRoutingDataSource. It essentially provides a way to keep a Map of DataSourcees as well as a callback method to return a key to be used to lookup the DataSource to be used eventually. The implementation of this method usually looks up some thread bound key and return that (or even maps that onto a DataSource map key in turn). You just have to make sure some web component binds that key to the thread in the first place.
If you have that in place your Spring configuration just sets up a bean for your sub-class of AbstractRoutingDataSource and pipes the map of DataSources into it. Your Spring Data JPA setup stays the default way. The EntityManagerFactoryBean refers to the AbstractRoutingDataSource and you have a single <jpa:repositories /> element only.
I'm using Spring's SchedulerFactoryBean to run some Quartz jobs within a Spring based java application. At present, this is a single instance application in development, but as soon as we start horizontally scaling this we will want to use a jdbc based JobStore for Quartz so no more than one app will run a given job.
Right now, SchedulerFactoryBean is configured as follows:
<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" >
<property name="taskExecutor" ref="taskExecutor"/>
<property name="triggers">
<list>
<!-- a bunch of triggers here -->
</list>
<property name="applicationContextSchedulerContextKey">
<value>applicationContext</value>
</property>
</bean>
and with using a jdbc based JobStore it will look like this
<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" >
<property name="dataSource" ref="mysqlJobDataSource"/>
<property name="taskExecutor" ref="taskExecutor"/>
<property name="triggers">
<list>
<!-- a bunch of triggers here -->
</list>
</property>
<property name="applicationContextSchedulerContextKey">
<value>applicationContext</value>
</property>
<property name="quartzProperties">
<props>
<prop key="org.quartz.jobStore.class">org.quartz.impl.jdbcjobstore.JobStoreTX</prop>
<prop key="org.quartz.jobStore.driverDelegateClass">org.quartz.impl.jdbcjobstore.StdJDBCDelegate</prop>
<!-- and a bunch of other quartz props -->
</props>
</property>
</bean>
Ideally, I'd like to continue using the default RAMJobStore version (the first one) for developers, but use the jdbc version for deployed environments. However, there doesn't seem to be a very good way to switch between the two through something like a property, since the jdbc store involves lots more configuration and the mere existence of the dataSource property on SchedulerFactoryBean means it tries to a JDBC based job store.
Also, Since SchedulerFactoryBean is an initializing bean where the initializing basically starts running all of the jobs, so I can't have both of those beans defined in a config file loaded into the spring context either, which means I'll have parallel jobs running.
I've also read through this answer, but this situtation differs in that I'm dealing with two InitializingBeans that should never be in the same context at the same time.
What would be the simplest way to configure switching between these two configurations of SchedulerFactoryBean?
From Spring 3.1 you can use Spring profiles:
<bean name="schedulerFactoryBean" profile="dev" ...
<bean name="schedulerFactoryBean" profile="prd" ...
Then you can instruct Spring container which profile to use, see How to set active spring 3.1 environment profile via a properites file and not via an env variable or system property and Spring autowire a stubbed service - duplicate bean.
If you can't use 3.1 or profiles, the old-school of solving such issues is to have two context files: schedulerContext-dev.xml and schedulerContext-prd.xml`. Then you can import them selectively:
<import resource="schedulerContext-${some.property}"/>
A better option would be using quartz properties file. As part of your release you can have different files per environment. The context that way is the same for all the environments, the only thing that changes is the configuration file. Using maven profiles you can solve it