We have migrated a legacy application from hibernate 4.3.10.Final to 5.2.10.Final including spring version to 4.3.10.RELEASE.
We have then changed the following configuration.
Spring context:
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
hibernate.cfg.xml:
<property name="hibernate.transaction.jta.platform">org.hibernate.engine.transaction.jta.platform.internal.JBossAppServerJtaPlatform</property>
<property name="hibernate.transaction.factory_class">org.hibernate.engine.transaction.internal.jta.JtaTransactionFactory</property>
<property name="hibernate.current_session_context_class">jta</property>
to
Spring context:
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
hibernate.cfg.xml:
<property name="hibernate.transaction.jta.platform">JBossAS</property>
<property name="hibernate.transaction.coordinator_class">jta</property>
<property name="hibernate.current_session_context_class">jta</property>
<!-- BMT. Default is false see org.hibernate.cfg.AvailableSettings#PREFER_USER_TRANSACTION. -->
<property name="hibernate.jta.prefer_user_transaction">true</property>
However, the application doesn't behave as it did in hibernate 4.3 as it seems that the application is auto flushing and behaving as CMT would.
Here is a scenario. In the simpliest form.
#Transactional()
ObjectA.assemble(...)
ObjectA objectA = new ObjectA();
ObjectB objectB = objectBAssemblerImpl.assemble(...); /* objectBAssemblerImpl.assemble doesn't contain the #Transactional annotation. */
hibernate.saveorupdate(objectB);
objectA.setObjectB(objectB);
Objectc objectC = hibernate.findById(ObjectC.class, 4);
objectA.setObjectC(objectC);
objectA.set...()
When line hibernate.findById() is executed, hibernate performs a flush however when the same sceanrio is done within hibernate 4.3 it doesn't.
Can someone help to determine how JTA BMT should be configired in hibernate 5 / Spring 4.3 using hibernate's legacy bootstrap? Have i missed something?
Related
I'm observing seemingly weird behavior related to how Spring handles operations with multiple data sources, especially participation in transaction synchronization.
My Spring context has two data sources configured:
1) dataSource1 - MySQL database
2) dataSource2 - Apache Impala database
Both data sources have a jdbc template configured for them. Additionally dataSource1 has a transaction manager configured. dataSource2 has no transaction manager configured (Apache Impala does not have transactions by design, it just happens to expose SQL-like querying functionality via JDBC connector).
I'm using this configuration in a spring-batch application - dataSource1 and its transactionManager is set to be used to store data related to spring-batch job meta-info.
Next I have a spring-batch job configured with a single custom Tasklet step. In this step I'm accessing dataSource2 via its jdbc template. And this is where the problem occurs - to my surprise connection to dataSource2 starts to participate in a transaction synchronization.
2018-06-06 10:41:08,179 DEBUG [main] org.springframework.jdbc.datasource.DataSourceUtils - Registering transaction synchronization for JDBC Connection
I understand that upon a start of a spring-batch step a transaction related to dataSource1 is started however why should dataSource2 be anyhow involved in that?
A negative side-effect is that once connection to dataSource2 starts to participate in transaction synchronization the connection is not closed after e.g. jdbcTemplate.execute(...) command completes. Essentially what I'm observing is that open connections to dataSource2 are closed only when the outer transaction completes.
Is there a way to configure Spring context and dataSource2 to not participate in a transaction synchronization?
Configuration
<bean id="dataSource1" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<constructor-arg ref="hikariConfig" />
</bean>
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
<property name="poolName" value="springHikariCP" />
<property name="dataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlDataSource" />
...
</bean>
<bean id="dataSource1JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource1"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" p:entityManagerFactory-ref="entityManagerFactory"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" p:dataSource-ref="dataSource1">
<property name="packagesToScan" value="..."/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="sharedCacheMode" value="DISABLE_SELECTIVE"/>
</bean>
<bean id="dataSource2" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="org.apache.hive.jdbc.HiveDriver"/>
...
</bean>
<bean id="dataSource2JdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource2"/>
</bean>
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>
I understand that this is a very long question, but i wanted to ask everything because i'm
stuck with these things for more than 2 weeks and i'm in a situation to solve this within
this week. Please guide me in this matter.
I'm Using EclipseLink jpa version 2, Spring 3, jdk6, MySQL5 and tomcat7.
I have configured the following in each of my DAO classes.
#PersistenceContext
private EntityManager em;
I have the following in my Spring xml:
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
<property name="url" value="jdbc:mysql://localhost:3306/xxxxx"/>
<property name="username" value="xxxx"/>
<property name="password" value="xxxx"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
</bean>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<property name="jpaDialect" ref="jpaDialect"/>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
<property name="jpaDialect" ref="jpaDialect"/>
</bean>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter" >
<property name="showSql" value="true"/>
<property name="generateDdl" value="true" />
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect"/>
From Persistence.xml:
<persistence-unit name="xxxxx" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<-- class mappings -->
</persistence-unit>
I've got few confusion about what i have done:
Is the EntityManager injected by Spring? (I understand that #PersistenceContext is a
J2EE annotation, so wondering whether it is injected without Spring's contribution).
As i have already mentioned, i have injected EntityManager in all the DAO classes. Is
this a good practice? or should i make it Singleton by having a separate class like
PersistenceManager, which has EntityManager attribute wired, and have
getEntityManager() method?
As you can see above, i have configured Spring transactions. But when i do CRUD
operations continuously for 2-3 times, application gets stuck and fails with EclipseLink
exception saying unable to get lock, timeout etc. Am i doing anything wrong here or
missing any transaction configurations??
With the above configurations, i can only use #Transactional annotation with default
values which are PROPAGATION_REQUIRED,ISOLATION_DEFAULT. If i change these for any other
values, such as #Transactional(PROPAGATION_REQUIRED,ISOLATION_SERIALIZABLE) etc,
application throws exception as Custom isolation levels are not supported. Again, am
i missing any configurations?
Thanks.
Yes, spring recognizes the #PersistenceContext annotation and injects the entity manager
Spring takes care of that - it injects the same EntityManager instance in all DAOs. In fact, it injects a proxy so that each request uses a different entity manager.
Normally everything should run fine. You need <tx:annotation-driven /> in order to use #Transactional
JPA only supports the default isolation level. You can work this around by customizing the spring jpa dialect, but there's nothing built-in. The way to go is extend XJpaDialect (in your case X=EclipseLink), override the beingTransaction, obtain the Connection (in an eclipse-link specific way), set the desired isolation level (accessible through the transaction definition), and configure this as a property of your LocalContainerEntityManagerFactoryBean:
<property name="jpaDialect">
<bean class="com.foo.util.persistence.EclipseLinkExtendedJpaDialect" />
</property>
I'm having a problem getting Hibernate Envers to work in our environment. We are using Spring 3.x with LoadTimeWeaving. Below is our context file:
<context:annotation-config/>
<context:spring-configured/>
<context:load-time-weaver aspectj-weaving="autodetect"/>
<context:component-scan base-package="com.viridityenergy.vpower"/>
<context:property-placeholder location="classpath:db/database-test.properties"/>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<bean id="dataSourcePooled"
class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close"
p:jdbcUrl="${database.url}"
p:user="${database.username}"
p:password="${database.password}"
p:initialPoolSize="1"
p:maxPoolSize="5"
p:idleConnectionTestPeriod="500"
p:acquireIncrement="1"
p:maxStatements="50"
p:numHelperThreads="1"
p:autoCommitOnClose="true"/>
<bean id="jpaAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
p:databasePlatform="${database.platform}"
p:showSql="${database.showSql}"
p:generateDdl="${database.generateDdl}"/>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:persistenceUnitName="TEST"
p:persistenceXmlLocation="META-INF/persistence.xml"
p:dataSource-ref="dataSourcePooled"
p:jpaVendorAdapter-ref="jpaAdapter">
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory"
p:dataSource-ref="dataSourcePooled"/>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
Here is our persistence.xml
<persistence-unit name="TEST" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.ejb.event.post-insert"
value="org.hibernate.envers.event.AuditEventListener"/>
<property name="hibernate.ejb.event.post-update"
value="org.hibernate.envers.event.AuditEventListener"/>
<property name="hibernate.ejb.event.post-delete"
value="org.hibernate.envers.event.AuditEventListener"/>
<property name="hibernate.ejb.event.pre-collection-update"
value="org.hibernate.envers.event.AuditEventListener"/>
<property name="hibernate.ejb.event.pre-collection-remove"
value="org.hibernate.envers.event.AuditEventListener"/>
<property name="hibernate.ejb.event.post-collection-recreate"
value="org.hibernate.envers.event.AuditEventListener"/>
</properties>
</persistence-unit>
The audit tables are setup correctly, but when an entity is persisted there are no records stored in the audit tables. There are only two fields that are audited. Also, because we are using loadTimeWeaving, when we run unit test, we are required to have -javaagent:/Users/TEST/.m2/repository/org/springframework/spring-instrument/3.0.3.RELEASE/spring-instrument-3.0.3.RELEASE.jar as a JVM argument so the loadTimeWeaving works.
Aside from Envers, everything else works fine.
Any help would be much appreciated.
I found out what the problem was, so for anyone else who may be experiencing this, here it is. Envers was actually working all along. What I didn't realize was that in my unit tests, everything was wrapped in a single transaction and then rolled back. Envers will not commit to the audit table until the initial transaction commits and is complete.
The fix was to set the test up as an integration test without a rollback. Then my audit records started showing up.
I have a Spring web application which is configured to use JDK proxying for AOP. The AOP annotations (such as #Transactional) are declared on the interfaces, rather than the implementation classes.
The application itself works fine, but when I run the unit tests, it seems to be attempting to use CGLIB for the AOP functionality (instead of JDK proxying). This causes the tests to fail - I've appended the stack trace below.
I don't understand why CGLIB is being used when I run the tests, because the Spring configuration is largely the same as when the application is running. One possibly significant difference is that the test configuration uses a DataSourceTransactionManager instead of a JTA transaction manager. The test classes themselves all extend AbstractJUnit4SpringContextTests, could it be that this class is somehow hard-wired to use CGLIB?
Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class $Proxy25]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class $Proxy25
at org.springframework.aop.framework.Cglib2AopProxy.getProxy(Cglib2AopProxy.java:213)
at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:110)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:488)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:363)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:324)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:361)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1343)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473)
... 79 more
Caused by: java.lang.IllegalArgumentException: Cannot subclass final class class $Proxy25
at net.sf.cglib.proxy.Enhancer.generateClass(Enhancer.java:446)
at net.sf.cglib.transform.TransformingClassGenerator.generateClass(TransformingClassGenerator.java:33)
at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:285)
at org.springframework.aop.framework.Cglib2AopProxy.getProxy(Cglib2AopProxy.java:201)
... 86 more
EDIT: One of the commentators requested that I post the Spring configuration. I've included it below in abbreviated form (i.e. irrelevant beans and XML namespaces omitted).
spring-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<!-- ANNOTATION SUPPORT -->
<!-- Include basic annotation support -->
<context:annotation-config/>
<!-- CONTROLLERS -->
<!-- Controllers, force scanning -->
<context:component-scan base-package="com.onebigplanet.web.controller,com.onebigplanet.web.ws.*"/>
<!-- Post-processor for #Aspect annotated beans, which converts them into AOP advice -->
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator">
<property name="proxyTargetClass" value="true"/>
</bean>
<!-- An #Aspect bean that converts exceptions thrown in POJO service implementation classes to runtime exceptions -->
<bean id="permissionAdvisor" class="com.onebigplanet.web.advisor.PermissionAdvisor"/>
<bean id="businessIntelligenceAdvisor" class="com.onebigplanet.web.advisor.bi.BusinessIntelligenceAdvisor"/>
<!-- Finds the controllers and sets an interceptor on each one -->
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list>
<bean class="com.onebigplanet.web.interceptor.PortalInterceptor"/>
</list>
</property>
</bean>
<!-- METHOD HANDLER ADAPTER -->
<!-- Finds mapping of url through annotation on methods of Controller -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="cacheSeconds" value="0"/>
<property name="webBindingInitializer">
<bean class="com.onebigplanet.web.binder.WebBindingInitializer"/>
</property>
</bean>
</beans>
applicationContext-service.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<!-- Declares a bunch of bean post-processors -->
<context:annotation-config/>
<context:component-scan base-package="com.onebigplanet.service.impl,com.onebigplanet.dao.impl.mysql" annotation-config="false"/>
<!-- Property configurer -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="/WEB-INF/obp-service.properties" />
</bean>
<!-- Post-processor for #Aspect annotated beans, which converts them into AOP advice -->
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
<!-- An #Aspect bean that converts exceptions thrown in service implementation classes to runtime exceptions -->
<bean id="exceptionAdvisor" class="com.onebigplanet.service.advisor.ExceptionAdvisor"/>
<bean id="cachingAdvisor" class="com.onebigplanet.service.advisor.CacheAdvisor"/>
<bean id="businessIntelligenceAffiliateAdvisor" class="com.onebigplanet.service.advisor.BusinessIntelligenceAffiliateAdvisor"/>
<!-- Writable datasource -->
<jee:jndi-lookup id="dataSource" jndi-name="java:/ObpDS"/>
<!-- ReadOnly datasource -->
<jee:jndi-lookup id="readOnlyDataSource" jndi-name="java:/ObpReadOnlyDS"/>
<!-- Map the transaction manager to allow easy lookup of a UserTransaction -->
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
<!-- Annotation driven transaction management -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
applicationContext-test.xml This is only included when running the unit tests. It's purpose is to overwrite some of the beans declared in the other config files.
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<!-- Overwrite the property configurer bean such that it reads the test properties file instead -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="/obp-test.properties"/>
</bean>
<!-- All DAOs should use the test datasource -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${testDataSource.driverClassName}"/>
<property name="url" value="${testDataSource.url}"/>
<property name="username" value="${testDataSource.username}"/>
<property name="password" value="${testDataSource.password}"/>
</bean>
<bean id="readOnlyDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${testDataSource.driverClassName}"/>
<property name="url" value="${testDataSource.url}"/>
<property name="username" value="${testDataSource.username}"/>
<property name="password" value="${testDataSource.password}"/>
</bean>
<!--
Overwrite the JTA transaction manager bean defined in applicationContent-service.xml with this one because
the implementation of the former is provided by JBoss
-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<beans>
Sounds like you're referencing an implementation class instead of an interface. There is an excerpt here with more detail.
A Spring forum post: "Mixing JDK and CGLIB proxies"
A great blog post explaining pros and cons of JDK vs. CGLIB proxies.
Hey Jean, CGLib proxies are created by subclassing the class to be proxied -- you're attempting to proxy another proxy which isn't allowed since proxies are themselves final classes. Hence:
Caused by: java.lang.IllegalArgumentException: Cannot subclass final class class $Proxy25
I don't know if the solution was already shared and I am also sure the original requester must have found a solution, since it is a one year old query. For public interest however let me mention it here. Spring was using CGLIB because of the following declaration.
<!-- Post-processor for #Aspect annotated beans, which converts them into AOP advice -->
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator">
<property name="proxyTargetClass" value="true"/>
</bean>
The property should be set to false, so that the CGLIB is not triggered instead JDK Dynamic Proxying.
<property name="proxyTargetClass" value="false"/>
Hope that helps.