I am running a tasklet using Spring batch (4.1.4.RELEASE) and Spring jars (4.0.9.RELEASE) and getting the exception:
Caused by: java.lang.IllegalStateException: A transaction manager must be provided**
at org.springframework.util.Assert.state(Assert.java:385) ~[spring-core-4.0.9.RELEASE.jar:4.0.9.RELEASE]
at org.springframework.batch.core.step.tasklet.TaskletStep.afterPropertiesSet(TaskletStep.java:129) ~[spring-batch-core-4.1.4.RELEASE.jar:4.1.4.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1613) ~[spring-beans-4.0.9.RELEASE.jar:4.0.9.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1550) ~[spring-beans-4.0.9.RELEASE.jar:4.0.9.RELEASE]
... 41 more
Below I have shown the session factory XML-based configuration.
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
<property name="hibernateProperties">
<value>
hibernate.show_sql=false
hibernate.format_sql=false
hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
hibernate.query.substitutions=true 'Y', false 'N'
hibernate.cache.use_second_level_cache=true
hibernate.cache.provider_class=net.sf.ehcache.hibernate.SingletonEhCacheProvider
hibernate.cache.use_query_cache=true
</value>
</property>
</bean>
<bean id="jdbcTransactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
lazy-init="true">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="hibernatetransactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager"
lazy-init="true">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
I have tried some changes in Spring batch and Spring core library versions but nothing is working and I am getting the same exception.
The error happens in org.springframework.batch.core.step.tasklet.TaskletStep.afterPropertiesSet(TaskletStep.java:129) ~[spring-batch-core-4.1.4.RELEASE.jar:4.1.4.RELEASE], which means you did not set a transaction manager on your tasklet.
You did not share your tasklet's configuration, but you need to make sure a transaction manager is set on it, this is a mandatory property.
Related
i have the following declared in spring.xml:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
...
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- Adapters -->
<bean id="ADBAdapter" class="model.adapter.ADBAdapter">
<constructor-arg>
<ref bean="sessionFactory" />
</constructor-arg>
</bean>
So after i created the context. I can Access my ADBAdapter and do stuff.
The Problem is, that i want to use ADBAdapter in another Thread.
But then i get sometimes a SessionClosed Exception, because the session gets closed in the parent thread.
How can I handle this ?
Thank you for your help
In hibernate you can use
hibernate.current_session_context_class=thread
I previously had this config for Hibernate using RESOURCE-LOCAL transaction type:
persistence.xml:
<persistence-unit name="myPU" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
</persistence-unit>
applicationContext (dataaccess bit):
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" p:entityManagerFactory-ref="entityManagerFactory"></bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaAdapter" />
<property name="persistenceUnitName" value="myPU"/>
<property name="jpaProperties">
<props>
<prop key="javax.persistence.validation.mode">none</prop>
</props>
</property>
</bean>
<bean id="entityManager" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.jpa.vendor.HibernateJpaSessionFactoryBean">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<!-- Are there any other properties required? -->
</bean>
<bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="false" />
</bean>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/CNTXESDB" />
<property name="lookupOnStartup" value="true" />
<property name="cache" value="true" />
<property name="proxyInterface" value="javax.sql.DataSource" />
</bean>
But this kind of transaction seems not to work with Glassfish, so I had to switch to JTA transactions.
The problem is -- to get Spring to manage transaction creation (through #Transactional) I need to define a TransactionManager bean but JtaTransactionManager included in spring-tx does not accept an entityManagerFactory bean, so it does not know where the entityManager is in order to open/close/flush Hibernate session.
So how can I configure Spring with Hibernate to use JTA transactions?
EDIT:
turns out you can use RESOURCE_LOCAL transactions with Glassfish, but somehow you cannot have a persistence.xml file. I renamed this file to my_persistence.xml and configured LocalContainerEntityManagerFactoryBean like this:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaAdapter" />
<property name="persistenceUnitName" value="myPU"/>
<property name="persistenceXmlLocation" value="classpath:META-INF/my_persistence.xml" />
<property name="jpaProperties">
<props>
<prop key="javax.persistence.validation.mode">none</prop>
</props>
</property>
</bean>
I had a similar problem and finally I solved as you can see in this little demo:
https://github.com/miguelangelprogramacion/spring4_jpa_hibernate
With [1] as a reference, I prefer to use Spring's Transaction Support before JTA.
Also, I've used an annotation based approach.
[1] http://spring.io/blog/2011/08/15/configuring-spring-and-jta-without-full-java-ee/
I am using Spring and trying to setup a global transaction spanning over two MS SQL Server DBs. The app is running inside Tomcat 6.
I have these definitions:
<bean id="dataSource1" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
....
</bean>
<bean id="sessionFactory1"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource1"/>
....
</bean>
<bean id="hibernateTransactionManager1"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory1"/>
</property>
</bean>
<bean id="dataSource2" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
....
</bean>
<bean id="sessionFactory2"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource2"/>
....
</bean>
<bean id="hibernateTransactionManager2"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory2"/>
</property>
</bean>
Then also, each DAO is linked either to sessionFactory1 or to sessionFactory2.
<bean name="stateHibernateDao" class="com.project.dao.StateHibernateDao">
<property name="sessionFactory" ref="sessionFactory1"/>
</bean>
Also, I recently added these two.
<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close">
<property name="forceShutdown" value="false" />
<property name="transactionTimeout" value="300" />
</bean>
<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
<property name="transactionTimeout" value="300" />
</bean>
I am trying to programmatically manage the global transaction
(this is some old legacy code and I don't want to change it too
much so I prefer keeping this managed programmatically).
So now I have this UserTransaction ut (injected from Spring), so I call ut.begin(), do some DB/DAO operations to the two DBs through the DAOs, then I call ut.commit().
The thing is that even before the ut.commit() call, I can see the data is already committed to the DBs?!
I don't think Atomikos is aware of my two DBs, their data sources, session factories, etc. I don't think it starts any transactions on them. Looks like they are not enlisted at all in the global transaction.
To me it seems that each DB/DAO operation goes to the SQL Server on its own, so SQL Server creates an implicit transaction for just that DAO/DB operation, applies the operation and commits the implicit the transaction.
But 1) and 2) are just guesses of mine.
My questions:
Do I need to start the two DB transactions myself (but OK, this is what I am currently doing and I am trying to get rid of; that's why I am trying to use Atomikos to start with)?
How I can configure all this correctly so that when I call ut.begin() it begins a global transaction to the two DBs and when I call ut.commit() it commits it?
I haven't played with JTA recently so seems to me I am missing something quite basic here. What is it?
Edit 1
<bean id="globalTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="userTransaction" ref="atomikosUserTransaction"/>
<property name="transactionManager" ref="atomikosTransactionManager" />
<property name="allowCustomIsolationLevels" value="true" />
<property name="transactionSynchronization" value="2" />
</bean>
I have simple application with following folder structure:
ProjFolder
|-----src
|----------packagename
|---------------{sourcefiles}
|----------META-INF
|---------------{beans.xml}
|---------------{hibernate.cfg.xml}
|---------------{EntityMapping.hbm.xml}
here is the part of beans.xml Spring config file:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:./META-INF/jdbc.properties" />
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:./META-INF/hibernate.cfg.xml" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>classpath:./META-INF/EntityMapping.hbm.xml</value>
</list>
</property>
</bean>
<tx:annotation-driven transaction-manager="txManager" />
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
when i start my unit tests i getting following exception:
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'wrapperClass' defined in class path resource
[META-INF/beans.xml]: Cannot resolve reference to bean 'wrapperClassField'
while setting constructor argument; nested exception is
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'xmlBooksource' defined in class path resource
[META-INF/beans.xml]: Cannot resolve reference to bean
'sessionFactory' while setting bean property 'sessionFactory'; nested
exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'sessionFactory' defined in class path
resource [META-INF/beans.xml]: Invocation of init method failed;
nested exception is java.io.FileNotFoundException: class path resource
[classpath:/META-INF/EntityMapping.hbm.xml] cannot be opened because it does not exist
The same exception is thrown when i type
<property name="mappingResources">
<list>
<value>EntityMapping.hbm.xml</value>
</list>
</property>
Why spring cant find this file and how i must fill its location to make this code work?
Thanks in advance.
Have you tried removing the classpath: prefix? In looking at the Hibernate code, the mappingResources setter expects passes the strings to new ClassPathResource(String). This expects classpath resources already. The string then gets passed to ClassLoader.getResourceAsStream(String). None of this code would strip the "classpath:" prefix from the front of the resource string.
I'm not sure the error message is consistent with the beans.xml content you posted.
In the error you have
[classpath:/META-INF/EntityMapping.hbm.xml]
which isn't the same as
classpath:./META-INF/EntityMapping.hbm.xml
Notice the missing "." at the beginning in the error.
The second beans.xml configuration, should probably produce a different error message with:
[classpath:EntityMapping.hbm.xml]
This would be searching for the file in the root of your compiled application (jar, war, exploded, what have you).
I have successfully configure Hibernate 4 with Spring 3.1. My applicationContext.xml file is inside web-inf folder and has the following hibernate cofiguration:
<!-- Session Factory Declaration -->
<bean id="SessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="DataSource" />
<!--
<property name="annotatedClasses">
<list>
<value>iltaf.models.Levels</value>
</list>
</property>
-->
<property name="mappingLocations" value="classpath:iltaf/models/*.hbm.xml" />
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<!-- Enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="txManager"/>
<!-- Transaction Manager is defined -->
<bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="SessionFactory"/>
</bean>
</beans>
and I have separate hibernate.cfg.xml file inside my src folder. I am using Eclipse Juno Java EE version.
I'm trying to add one more database/schema/persistenceUnit in my project and I'm receiving the error:
No unique bean of type [javax.persistence.EntityManagerFactory] is defined: expected single bean but found 2
I google/api allot and could not found why spring is complaining about my configuration.
Here is part of my applicationContext.xml
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="transactionManager" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="${show.hibernate.sql}" />
<property name="generateDdl" value="false" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect" />
</bean>
</property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${database.driver}" />
<property name="url" ...
<property name="testOnBorrow" value="true" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="entityManagerFactoryREST" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSourceREST" />
<property name="persistenceUnitName" value="REST" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="${show.hibernate.sql}" />
<property name="generateDdl" value="false" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect" />
</bean>
</property>
</bean>
<bean id="dataSourceREST" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${database.driver}" />
...
<property name="testOnBorrow" value="true" />
</bean>
<bean id="transactionManagerREST" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryREST" />
</bean>
<tx:annotation-driven transaction-manager="REST"/>
<tx:annotation-driven transaction-manager="transactionManager"/>
Some questions:
Do I need to have two tx:annotation-driven ?
Do I need to specify persistenceUnitName in the factory ?
I'm putting some notes of my digg in spring forum (LINK)
Well thats it... any help will be glad!
With Spring, you need to have only one EntityManagerFactory.
What you are looking for is describe in the Spring documentation at the chapiter 13.5.1.4 : "Deals with multiple persitence units"
I copy/paste the text :
"13.5.1.4 Dealing with multiple persistence units
For applications that rely on multiple persistence units locations, stored in various JARS in the classpath, for example, Spring offers the PersistenceUnitManager to act as a central repository and to avoid the persistence units discovery process, which can be expensive. The default implementation allows multiple locations to be specified that are parsed and later retrieved through the persistence unit name. (By default, the classpath is searched for META-INF/persistence.xml files.)
<bean id="pum" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="persistenceXmlLocations">
<list>
<value>org/springframework/orm/jpa/domain/persistence-multi.xml</value>
<value>classpath:/my/package/**/custom-persistence.xml</value>
<value>classpath*:META-INF/persistence.xml</value>
</list>
</property>
<property name="dataSources">
<map>
<entry key="localDataSource" value-ref="local-db"/>
<entry key="remoteDataSource" value-ref="remote-db"/>
</map>
</property>
<!-- if no datasource is specified, use this one -->
<property name="defaultDataSource" ref="remoteDataSource"/>
</bean>
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitManager" ref="pum"/>
<property name="persistenceUnitName" value="myCustomUnit"/>
</bean>
The default implementation allows customization of the PersistenceUnitInfo instances, before they are fed to the JPA provider, declaratively through its properties, which affect all hosted units, or programmatically, through the PersistenceUnitPostProcessor, which allows persistence unit selection. If no PersistenceUnitManager is specified, one is created and used internally by LocalContainerEntityManagerFactoryBean."
This exceptions means that you are trying to autowire EntityManagerFactory by type. Do you have any #Autowired annotation in your code?
Aslo, when using #PersistenceContext, set the unit attribute correctly. And (I'm not sure if this is a proper thing to do) - try setting the name attribute to your respective factory name.
Also, check if you haven't copy-pasted incorrectly the REST transaction manager - now there is no such bean REST
Ensure all of your #PersistenceContext specify unitName. I haven't figured out how to tell Spring that a particular EMF or PersistenceUnit is the default. I thought specifying primary="true" on the default EMF would work but doesn't appear to
Do I need to specify persistenceUnitName in the factory ?
If you've got multiple persistence units, you do need to specify which ones the factories will use.
More to the heart of the matter, see SPR-3955. To summarize, versions prior to Spring 3.0M4 do not support multiple transaction managers with #Transactional. Nor do I believe it honors the "unitName" attribute for #PersistenceContext, so you can't specify that either.
For an example of how I worked around this by explicitly injecting EntityManagerFactorys and using AOP to re-enable #Transactional, see my sample app