I have been struggling through trying to build a very simple application that deploys to tomee using spring, hibernate and JMS. I believe that all of my configurations are correct (have the mysql xa data source and the xa active mq connection factory) but things aren't working as I would expect. Currently I have a simple service that writes using the injected entity manager then pushes to JMS within one method that is annotated as being transactional (spring annotation) but my message listener is being delivered these messages before the transaction is committed in spring.
I've tried using JMS template and the xa connection factory directly, but neither works properly. The template is configured with the jta transaction manager received from jndi. Any ideas what to look at for hints as to why the JMS sends are not participating in the same transaction as the database writes?
Spring Configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:encryption="http://www.jasypt.org/schema/encryption"
xmlns:jms="http://www.springframework.org/schema/jms"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.directwebremoting.org/schema/spring-dwr http://www.directwebremoting.org/schema/spring-dwr-3.0.xsd
http://www.jasypt.org/schema/encryption http://www.jasypt.org/schema/encryption/jasypt-spring31-encryption-1.xsd
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.1.xsd"
default-autowire="byType" default-lazy-init="false">
<context:component-scan annotation-config="false" base-package="org.superbiz" />
<bean class="org.springframework.orm.jpa.DefaultJpaDialect" />
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" />
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor">
<property name="alwaysUseJndiLookup" value="false" />
<property name="jndiFactory" >
<ref local="jndiFactory"/>
</property>
</bean>
<bean id="jndiFactory" class="org.springframework.jndi.support.SimpleJndiBeanFactory">
<property name="resourceRef" value="true" />
</bean>
<bean id="PrintTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory">
<ref local="jmsFactory" />
</property>
<property name="defaultDestinationName" value="resources/jms/PrintQueue" />
<property name="deliveryPersistent" value="true"/>
<!-- <property name="sessionTransacted" value="true"/> -->
<!-- <property name="sessionAcknowledgeMode" value="0"/> -->
</bean>
<bean id="PersistTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory">
<ref local="jmsFactory" />
</property>
<property name="defaultDestinationName" value="resources/jms/PersistQueue" />
<property name="deliveryPersistent" value="true"/>
<!-- <property name="sessionTransacted" value="true"/> -->
<!-- <property name="sessionAcknowledgeMode" value="0"/> -->
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">
<property name="defaultPersistenceUnitName" value="movie-unit" />
<property name="persistenceContexts">
<map>
<entry key="movie-unit" value="persistence/movie-unit" />
</map>
</property>
</bean>
<context:component-scan base-package="org.superbiz.ejb" annotation-config="false">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<jee:jndi-lookup id="jmsFactory" jndi-name="resources/jms/ConnectionFactory" expected-type="javax.jms.ConnectionFactory" />
<tx:jta-transaction-manager />
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="printBean" class="org.superbiz.mdb.PrintBean"/>
<bean id="persistBean" class="org.superbiz.mdb.PersistBean"/>
<jms:listener-container container-type="default" connection-factory="jmsFactory" cache="none" transaction-manager="transactionManager" concurrency="1" receive-timeout="1000" prefetch="-1">
<jms:listener destination="resources/jms/PrintQueue" ref="printBean" />
<jms:listener destination="resources/jms/PersistQueue" ref="persistBean" />
</jms:listener-container>
</beans>
tomee.xml (cobbled together from http://tomee-openejb.979440.n4.nabble.com/MDB-doesn-t-read-messages-td4666169.html)
<Resource id="ActiveMQResourceAdapter" type="ActiveMQResourceAdapter">
BrokerXmlConfig=broker:(vm://localhost)
</Resource>
<Resource id="resources/jms/ConnectionFactory" type="javax.jms.ConnectionFactory">
ResourceAdapter = ActiveMQResourceAdapter
</Resource>
<Resource id="resources/jms/XAConnectionFactory" class-name="org.apache.activemq.ActiveMQXAConnectionFactory">
BrokerURL = vm://localhost
ResourceAdapter = ActiveMQResourceAdapter
</Resource>
<Resource id="resources/jms/PrintQueue" type="javax.jms.Queue"/>
<Resource id="resources/jms/PersistQueue" type="javax.jms.Queue"/>
<Resource id="MySQL Database" type="DataSource">
JdbcDriver com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
JdbcUrl jdbc:mysql://localhost/test
UserName test
</Resource>
I've tried several ways to include not using the XAConnectionFactory with the JMSTemplate configured to be sessionTransacted and not, removing the JMSTemplate and creating the connection/session/producer/message from the connectionFactory, but I've run into an issue each time. With manually creating the connection/session/producer/message from the ConnectionFactory I notice that the 20 items I attempt to write to the database then send to another JMS Queue start being read before the services transaction completes.
As far as I can tell everything is configured correctly (although I could definitely be wrong since this was pulled from lots of places). My goal is to be able to use the JMSTemplate instead of manually creating the connection/session/etc myself, but I'm at a loss for why this is happening at this point so any ideas are greatly appreciated.
I've also bumped the logging of the Spring JtaTransactionManager up and I see the following happening when the #Transactional method is called
DEBUG org.springframework.transaction.jta.JtaTransactionManager - Creating new transaction with name [org.superbiz.ejb.Movies.send]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
DEBUG org.springframework.transaction.jta.JtaTransactionManager - Initiating transaction commit
Then I see the my MDB code trying to retrieve the item from the entityManager (which works/fails intermittently). When it succeeds I see this
printing from MDB: director: director0title: title0year: 0
DEBUG org.springframework.transaction.jta.JtaTransactionManager - Initiating transaction commit
DEBUG org.springframework.transaction.jta.JtaTransactionManager - Creating new transaction with name [org.springframework.jms.listener.DefaultMessageListenerContainer#0]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
When it fails I see this
/***************** BROKEN ***************/
/*******************435265*****************/
/***************** BROKEN ***************/
DEBUG org.springframework.transaction.jta.JtaTransactionManager - Initiating transaction commit
DEBUG org.springframework.transaction.jta.JtaTransactionManager - Creating new transaction with name [org.springframework.jms.listener.DefaultMessageListenerContainer#0]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
I've further cranked up the logging
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] DEBUG org.springframework.transaction.jta.JtaTransactionManager - Creating new transaction with name [org.springframework.jms.listener.DefaultMessageListenerContainer#1]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
**bold** [org.springframework.jms.listener.DefaultMessageListenerContainer#0-1] DEBUG org.springframework.transaction.jta.JtaTransactionManager - Creating new transaction with name [org.springframework.jms.listener.DefaultMessageListenerContainer#0]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Initializing transaction synchronization
[org.springframework.jms.listener.DefaultMessageListenerContainer#0-1] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Initializing transaction synchronization
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Bound value [org.springframework.jms.connection.JmsResourceHolder#81032a4] for key [org.apache.activemq.ra.ActiveMQConnectionFactory#5ee0c65d] to thread [org.springframework.jms.listener.DefaultMessageListenerContainer#1-1]
[org.springframework.jms.listener.DefaultMessageListenerContainer#0-1] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Bound value [org.springframework.jms.connection.JmsResourceHolder#eaebd86] for key [org.apache.activemq.ra.ActiveMQConnectionFactory#5ee0c65d] to thread [org.springframework.jms.listener.DefaultMessageListenerContainer#0-1]
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] DEBUG org.springframework.transaction.jta.JtaTransactionManager - Participating in existing transaction
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] TRACE org.springframework.transaction.interceptor.TransactionInterceptor - Getting transaction for [org.superbiz.mdb.PersistBean.onMessage]
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Retrieved value [org.springframework.jms.connection.JmsResourceHolder#81032a4] for key [org.apache.activemq.ra.ActiveMQConnectionFactory#5ee0c65d] bound to thread [org.springframework.jms.listener.DefaultMessageListenerContainer#1-1]
Persisted finished, but not yet committed
Leaving persist, should commit
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] TRACE org.springframework.transaction.interceptor.TransactionInterceptor - Completing transaction for [org.superbiz.mdb.PersistBean.onMessage]
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] TRACE org.springframework.transaction.jta.JtaTransactionManager - Triggering beforeCommit synchronization
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] TRACE org.springframework.transaction.jta.JtaTransactionManager - Triggering beforeCompletion synchronization
[org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] TRACE org.springframework.transaction.support.TransactionSynchronizationManager - Removed value [org.springframework.jms.connection.JmsResourceHolder#81032a4] for key [org.apache.activemq.ra.ActiveMQConnectionFactory#5ee0c65d] from thread [org.springframework.jms.listener.DefaultMessageListenerContainer#1-1]
**bold** [org.springframework.jms.listener.DefaultMessageListenerContainer#1-1] DEBUG org.springframework.transaction.jta.JtaTransactionManager - Initiating transaction commit
Entering print
/***************** BROKEN ***************/
/*******************597852*****************/
/***************** BROKEN ***************/
in this case DefaultMessageListenerContainer#1-1 is my Persist bean and 0-1 is a bean that retrieves the entity by id and then prints the content.
I am not 100% sure how to read this, but it's interesting to me that the DMLC#1-1 commits well after a new transaction has begun on DMLC#0-1, but DMLC#0-1 sees the message. I would have thought that DMLC#0-1 would have needed to start a new transaction to see this OR since he received the JMS message the entity should also be persisted to the database.
Contents of my persist bean
#Override
#Transactional
public void onMessage(Message message) {
TextMessage msg = (TextMessage)message;
int x;
try {
x = Integer.parseInt(msg.getText());
Movie movie = new Movie("director" + x, "title" + x, x);
entityManager.persist(movie);
final long id = movie.getId();
template.send(new MessageCreator() {
#Override
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage(Long.toString(id));
}
});
System.out.println("Persisted finished, but not yet committed");
System.out.println("Leaving persist, should commit");
} catch (Exception e) {
e.printStackTrace();
}
}
Contents of my print bean
public void onMessage(Message message) {
System.out.println("Entering print");
final TextMessage textMessage = (TextMessage) message;
try {
long id = Long.parseLong(textMessage.getText());
Movie movie = entityManager.find(Movie.class, id);
if(movie == null){
System.out.println("/***************** BROKEN ***************/");
System.out.println("/*******************" + id + "*****************/");
System.out.println("/***************** BROKEN ***************/");
} else {
System.out.println("updating: "+ movie);
}
} catch (Exception e) {
e.printStackTrace();
}
}
The entire app is available at https://github.com/jej2003/simple-spring, running a vanilla Tomee 1.7.1 with the necessary hibernate jars added to the tomee/lib directory.
I'm really at a loss here, does no one run JTA transactions in Tomee with Spring?
After a ton of debugging it turns out that the failure was not in the JTA implementation, but more so my understanding of JTA in general. While JTA ensures that both transactions will successfully commit, it does not enforce an order apparently of those transactions. The answer was ultimately provided here https://jira.spring.io/browse/SPR-12535, by Stéphane Nicoll.
Related
I am trying to configure Spring Boot, Apache Camel, ActiveMQ all togheter. This is what I did so far:
I run ActiveMQ using activemq.bat
I log into the console to monitor messages
I start backend service (sources below)
I start frontend service (Backend and Frontend are different spring boot projects)
I sucesfully send message into the que from frontend but after 20s I am getting timeout. The message appears in ActiveMQ console but it's not consumed by backend.
Here's how I configured backend:
build.gradle:
dependencies {
compile("org.apache.camel:camel-spring-boot:2.16.0")
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-websocket")
compile("org.springframework:spring-messaging")
compile("org.springframework:spring-jms")
compile("org.springframework.security:spring-security-web")
compile("org.springframework.security:spring-security-config")
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile('org.apache.camel:camel-jms:2.16.0')
compile("org.hibernate:hibernate-core:4.0.1.Final")
compile("mysql:mysql-connector-java:5.1.37")
compile("log4j:log4j:1.2.16")
compile("junit:junit:4.12")
compile("org.mockito:mockito-all:1.8.4")
compile('org.apache.activemq:activemq-core:5.7.0')
compile('com.epam.training.auction:auction_common:1.0')
testCompile("junit:junit")
}
Route Config: (I use UsersServiceImpl for testing and both ways of defining it don't work)
import org.apache.camel.RoutesBuilder;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.epam.training.auction_backend.services.UsersServiceImpl;
#Configuration
public class MyRouterConfiguration {
#Bean
public RoutesBuilder myRouter() {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from("jms:queue:auctions").to("bean:auctionsServiceImpl");
from("jms:queue:users").bean(UsersServiceImpl.class);
from("jms:queue:bidding").to("bean:biddingServiceImpl");
}
};
}
}
Client side, invoking method
#Override
public void registerUser(String username, String password) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("camel-client-remoting.xml");
UsersService usersService = context.getBean("usersServiceImpl", UsersService.class);
System.out.println("Invoking the logging");
UserTransferObject userTransferObject = new UserTransferObject("user", "pass");
usersService.addUser(userTransferObject);
System.out.println("User is logged");
IOHelper.close(context);
}
Client xml camel config
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:camel="http://camel.apache.org/schema/spring"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<camel:camelContext id="camel-client">
<camel:template id="camelTemplate"/>
<camel:proxy
id="auctionsServiceImpl"
serviceInterface="com.epam.training.auction.common.AuctionsService"
serviceUrl="jms:queue:auctions"/>
<camel:proxy
id="usersServiceImpl"
serviceInterface="com.epam.training.auction.common.UsersService"
serviceUrl="jms:queue:users"/>
<camel:proxy
id="biddingServiceImpl"
serviceInterface="com.epam.training.auction.common.BiddingService"
serviceUrl="jms:queue:bidding"/>
</camel:camelContext>
<bean id="jmsConnectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616"/>
</bean>
<bean id="pooledConnectionFactory"
class="org.apache.activemq.pool.PooledConnectionFactory"
init-method="start" destroy-method="stop">
<property name="maxConnections" value="8"/>
<property name="connectionFactory" ref="jmsConnectionFactory"/>
</bean>
<bean id="jmsConfig"
class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="pooledConnectionFactory"/>
<property name="concurrentConsumers" value="10"/>
</bean>
<bean id="jms"
class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="configuration" ref="jmsConfig"/>
<property name="transacted" value="true"/>
<property name="cacheLevelName" value="CACHE_CONSUMER"/>
</bean>
</beans>
During sending I also get warning:
2015-11-02 11:56:21.547 WARN 16328 --- [nio-8181-exec-5] o.s.b.f.s.DefaultListableBeanFactory : Bean creation exception on FactoryBean type check: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'usersServiceImpl': Invocation of init method failed; nested exception is org.apache.camel.ResolveEndpointFailedException: Failed to resolve endpoint: jms://queue:users due to: Cannot auto create component: jms
Common interfaces nad transfer objects are defined in 3rd project which is a dependency for both backend and frontend projects.
I feel that there's one missing part of this configuration. Please tell me what could it be.
Thanks in advance.
You need to change
<bean id="activemq"
class="org.apache.activemq.camel.component.ActiveMQComponent">
to
<bean id="jms"
class="org.apache.activemq.camel.component.ActiveMQComponent">
or change your endpoint urls to .to("activemq:queue:users").
The id of your ActiveMQComponent is the name used in the .to() to identify to camel that you want to use that component definition.
All API call are taking long time to respond because, spring is taking long time to return cached instance of singleton bean - transactionManager. Please see log, this behaviour is consistent for each request.
2
014-09-24 08:09:02,239 DEBUG servlet.DispatcherServlet - DispatcherServlet with name 'appServlet' processing GET request for [/emsp/locations]
2014-09-24 08:09:02,239 DEBUG annotation.RequestMappingHandlerMapping - Looking up handler method for path /locations
2014-09-24 08:09:02,239 DEBUG annotation.RequestMappingHandlerMapping - Did not find handler method for [/locations]
2014-09-24 08:09:02,239 DEBUG servlet.DispatcherServlet - Last-Modified value for [/emsp/locations] is: -1
2014-09-24 08:09:02,240 DEBUG support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'integrationEvaluationContext'
2014-09-24 08:09:02,241 DEBUG support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'endpointLookupService'
2014-09-24 08:09:07,407 DEBUG support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'txManager'
2014-09-24 08:09:07,407 DEBUG hibernate4.HibernateTransactionManager - Creating new transaction with name [com.***.emsp.service.impl.EndpointLookupServiceImpl.getEndpointLocations]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2014-09-24 08:09:07,407 DEBUG hibernate4.HibernateTransactionManager - Opened new Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] orphanRemovals=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] collectionQueuedOps=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])] for Hibernate transaction
2014-09-24 08:09:07,407 DEBUG hibernate4.HibernateTransactionManager - Preparing JDBC Connection of Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] orphanRemovals=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] collectionQueuedOps=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]
2014-09-24 08:09:07,407 DEBUG internal.LogicalConnectionImpl - Obtaining JDBC connection
2014-09-24 08:09:07,407 DEBUG resourcepool.BasicResourcePool - trace com.mchange.v2.resourcepool.BasicResourcePool#7cfea9ab [managed: 1, unused: 0, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection#6a4d7764)
2014-09-24 08:09:07,407 DEBUG internal.LogicalConnectionImpl - Obtained JDBC connection
2014-09-24 08:09:07,407 DEBUG spi.AbstractTransactionImpl - begin
2014-09-24 08:09:07,408 DEBUG jdbc.JdbcTransaction - initial autocommit status: true
2014-09-24 08:09:07,408 DEBUG jdbc.JdbcTransaction - disabling autocommit
2014-09-24 08:09:07,408 DEBUG hibernate4.HibernateTransactionManager - Exposing Hibernate transaction as JDBC transaction [com.mchange.v2.c3p0.impl.NewProxyConnection#3c0b2e6e]
2014-09-24 08:09:07,408 INFO impl.EndpointLookupServiceImpl - EndpointLookupServiceImpl::getEndpointLocations - called (Custom log - after this is almost instantaneous)
If you see these two lines specifically in the above line - there is a 5sec delay - this keeps increasing after a while but comes down once tomcat is restarted.
2014-09-24 08:09:02,241 DEBUG support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'endpointLookupService'
2014-09-24 08:09:07,407 DEBUG support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'txManager'
My spring config
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="com.****.emsp" />
<!-- Transaction Manager Declaration -->
<bean id="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
<tx:annotation-driven transaction-manager="txManager" />
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/emsp" />
<property name="user" value="***" />
<property name="password" value="***" />
<!-- C3P0 properties -->
<property name="acquireIncrement" value="1" />
<property name="minPoolSize" value="1" />
<property name="maxPoolSize" value="20" />
<property name="maxIdleTime" value="300" />
<property name="idleConnectionTestPeriod" value="3000" />
<!--property name="testConnectionOnCheckout" value="true" /> <property
name="preferredTestQuery" value="select 1;" / -->
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.****.emsp.entity" />
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=false
hibernate.hbm2ddl.auto=update
</value>
</property>
</bean>
</beans>
And i'm using #Transactional annotation for my service APIs involving DB transaction.
Please suggest how to go about debugging this. Also let me know if any another info is required.
Request Handling code:
#Service
public class EndpointLookupServiceImpl implements EndpointLookupService {
private static final Logger logger = Logger
.getLogger(EndpointLookupServiceImpl.class);
#Autowired
EndpointLocationDaoImpl endpointLoctionDao;
#Autowired
SsidDaoImpl ssidDao;
#Override
#Transactional
public EndpointLocationsResp getEndpointLocations(
String xJwtAssertionHeader, Map<String, List<String>> reqParams) {
logger.info("EndpointLookupServiceImpl::getEndpointLocations - called with xJwtAssertionHeader:"
+ xJwtAssertionHeader + " reqParams:" + reqParams);
.....
}
}
Using spring integration as controller for invoking the service:
<int-http:inbound-gateway id="endpointLocById"
request-channel="endpointLocByIdIn"
supported-methods="GET"
path="/locations/{locationId}"
mapped-request-headers="*"
payload-expression="#pathVariables.locationId" >
</int-http:inbound-gateway>
<int:channel id="endpointLocByIdIn"/>
<int:service-activator input-channel="endpointLocByIdIn" expression="#endpointLookupService.getEndpointLocationByLocationId(headers['x-jwt-assertion'], payload)" output-channel="out" />
Take thread dumps just before and after you see the blocking to see what your main thread is doing, Spring loads beans in a single thread, so you should be able to see where it is stuck and debug that even more.
I am trying to incorporate Spring transactions into my project, and it seems that they are not working. I went through some tutorials nad Spring docs, and for me everything seems OK.
What I have:
1) context file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="jdbcTemplate" class="webapp.dataaccess.commons.JdbcTemplateProvider">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- dao section -->
<bean id="modesDao" class="webapp.dataaccess.opcalc.basicdao.CalcModesData">
<property name="jdbc" ref="jdbcTemplate" />
</bean>
<!-- lots of DAO beans defined same way -->
2) data source defined on server:
<Resource name="jdbc/calc_webapp" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="user" password="password" driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://localhost:5432/service" defaultAutoCommit = "true" />
3) and finally in one of the DAO beans I have this method:
#Transactional(propagation=Propagation.REQUIRED)
public Boolean saveFullOrganization(OrganizationLevel org) throws Exception{
Boolean out = true;
try{
Integer adminPermKey = permDao.saveAdminPermissions(org.getPermissions().getAdminPermission());
org.getPermissions().setAdminPermissionKey(adminPermKey);
Integer sellPermKey = permDao.saveSellingPermissions(org.getPermissions().getSellingPermission());
org.getPermissions().setSellingPermissionKey(sellPermKey);
Integer dszPermKey = permDao.saveDszPermissions(org.getPermissions().getDszPermission());
org.getPermissions().setDszPermissionKey(dszPermKey);
Integer reportPermKey = permDao.saveReportingPermissions(org.getPermissions().getReportingPermission());
org.getPermissions().setReportingPermissionKey(reportPermKey);
if(org.getPermissions().getKey()==null){
Integer permissions = permDao.savePermissionsSet(org.getPermissions(), null);
org.setPermissionsKey(permissions);
}
saveOrganizationUnit(org, org.getKey());
}catch(Exception e){
e.printStackTrace();
throw e;
}
return out;
}
Flow is rather intuitive - first part of method prepares permission entries for organization unit (each operation in bean permDao is also transactional), then finally calls "saveOrganizationUnit" to finalize adding new entry. I assumed that with transaction management if any exception occure in the middle of that procedure, then no data from it will go to DB. But my tests proved that if I trigger artificial exception before "saveOrganizationUnit" operation (which interrupts whole process nad jumps out of the method) the permission part lands in DB anyway. So, as I understand, transactions are not working in my solution.
I am not sure what should I check and what can be wrong (I am kind of Spring noob, so please, don't kick if its something obvious).
Default behavour of #Transactional is defined as follows:
Any RuntimeException triggers rollback, and any checked Exception does not.
So, I guess you are throwing a checked exception. If you want to trigger rollback in this case, you need to configure #Transactional accordingly:
#Transactional(propagation=Propagation.REQUIRED, rollbackFor = Exception.class) ...
I am using Spring + JPA + Hibernate + EntityManager to talk to the database. I am getting 'A JTA EntityManager cannot use getTransaction()' error. Please provide your insights and help me resolve the issue.
beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans default-autowire="byName"
... xmlns definitions...
xsi:schemaLocation="...">
<context:component-scan base-package="com.mycompany.myproject" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" />
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="myDAO" class="com.mycompany.myproject.dao.myDAO" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven />
</beans>
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence ... xmlns definitions xsi:schemaLocation="..." version="1.0">
<persistence-unit name="TEST_DS">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/TEST_DS</jta-data-source>
<class>com.twinspires.exchange.model.Test</class>
<properties>
<property name="hibernate.archive.autodetection" value="class, hbm" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
<property name="hibernate.hbm2ddl.auto" value="validate" /> <!-- create-drop update -->
<property name="hibernate.cache.use_query_cache" value="true" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider" />
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
</properties>
</persistence-unit>
</persistence>
Exception Stack Trace (Excerpt)
15:47:43,340 INFO [STDOUT] DEBUG: org.springframework.transaction.annotation.AnnotationTransactionAttributeSource - Adding transactional method 'getName' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
15:47:43,343 INFO [STDOUT] DEBUG: org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'transactionManager'
15:47:43,356 INFO [STDOUT] DEBUG: org.springframework.orm.jpa.JpaTransactionManager - Creating new transaction with name [com.twinspires.exchange.dao.PicDAO.getName]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
15:47:44,114 INFO [STDOUT] DEBUG: org.springframework.orm.jpa.JpaTransactionManager - Opened new EntityManager [org.hibernate.ejb.EntityManagerImpl#c629e5] for JPA transaction
15:47:44,124 INFO [STDOUT] DEBUG: org.springframework.orm.jpa.JpaTransactionManager - Could not rollback EntityManager after failed transaction begin
15:47:44,125 INFO [STDOUT] java.lang.IllegalStateException: A JTA EntityManager cannot use getTransaction()
15:47:44,125 INFO [STDOUT] at org.hibernate.ejb.AbstractEntityManagerImpl.getTransaction(AbstractEntityManagerImpl.java:818)
15:47:44,126 INFO [STDOUT] at org.springframework.orm.jpa.JpaTransactionManager.closeEntityManagerAfterFailedBegin(JpaTransactionManager.java:412)
15:47:44,127 INFO [STDOUT] at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:381)
15:47:44,128 INFO [STDOUT] at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:371)
15:47:44,129 INFO [STDOUT] at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:335)
15:47:44,129 INFO [STDOUT] at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:105)
15:47:44,130 INFO [STDOUT] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
15:47:44,131 INFO [STDOUT] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
15:47:44,131 INFO [STDOUT] at $Proxy175.getName(Unknown Source)
Folowing is my dao class:-
public class MyDao implements IMyDao {
#PersistenceContext(unitName = "TEST_DS")
private EntityManager entityManager;
#Transactional
public String getName() {
final Query query = entityManager.createQuery("from TestTable");
final Object obj = query.getResultList().get(0);
return obj == null ? "Empty" : (String) obj;
}
}
Your help highly appreciated.
Remove the jta-datasource from persitence.xml, configure datasource as a bean j2ee:jdni-lookup and inject it into the LocalContainerEntityManagerFactoryBean
Remove this from persistence.xml
<jta-data-source>java:/TEST_DS</jta-data-source>
Configure the transaction-type to resource local
<persistence-unit name="TEST_DS" transaction-type="RESOURCE_LOCAL">
Change to your beans.xml
<j2ee:jndi-lookup id="dataSource" jndi-name="java:/TEST_DS"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
</bean>
First of all I want to tell you I had the same problem. Researching about that I found this page with your post and the answer by "gkamal".
I think that the answer comes to say that if you are trying to use "global" JTA transaction in your application and it doesn't work then don't use it, use in its place a "local" JDBC transaction.
But if you need to use global JTA transaction then you must use it.
Well I am going to give you the solution I found in my resarch.
There are properties that are application server dependent. I use glassfish and this solution works fine, but I think you are using JBOSS (due to the value you are using in the jta-data-source in your persistence.xml) I will write the values for a JBOSS AS, but in JBOSS AS I don't prove it, I just prove it only in glassfish.
In your persistence.xml you have to put another property:
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossStandAloneJtaPlatform"/>
The value of this property is AP server dependent.
In your beans.xml file you have to take a look in the entity manager factory and transaction manager. Morover you have indicate in your web.xml which persistence units you are referencing in your application.
beans.xml
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="TEST_DS"/>
</bean>
In your transaction manager you are using entity manager factory but you don't have to do that. You have to indicate the transaction manager and user transaction used by your app server, this way
<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManagerName" value="java:appserver/TransactionManager"/>
<property name="userTransactionName" value="java:comp/UserTransaction"/>
</bean>
The values of those properties are app server dependent (I use glassfish). I think you have to use the values for jboss ap:
<property name="transactionManagerName" value="java:/TransactionManager"/>
<property name="userTransactionName" value="UserTransaction"/>
But I didn't prove it.
Last, in glassfish I have to put in beans.xml (and I don't know why) the following bean (I think in jboss ap it isn't necessary but you might prove it)
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" >
<property name="persistenceUnits">
<map>
<entry key="TEST_DS" value="persistence/TEST_DS"/>
</map>
</property>
</bean>
In your web.xml you need reference the persistence units your application will use.
<persistence-unit-ref>
<persistence-unit-ref-name>persistence/TEST_DS</persistence-unit-ref-name>
<persistence-unit-name>TEST_DS</persistence-unit-name>
</persistence-unit-ref>
I hope that the solution is of help for you. It works for me.
Our application use IBM WAS6.1 container with EJB3.0 feature pack. Transactions are container managed via EJB3.0 transactions started from ejb service bean. We use Spring for DI. There are 3 layers. Spring DAO, Spring Service and EJB3.0 Bean Service.
Now i when i try to use OpenJPA with WAS6.1. EntityManager is successfully injected into SpringDAO but container closes EntityManager before transaction commits. (Datasource is JNDI datasource)
Here is the stacktrace:
[1/4/12 9:23:17:769 EET] 0000001f ExceptionUtil E CNTR0020E: EJB threw an unexpected (non-declared) exception during invocation of method "inquiryReconcilation" on bean "BeanId(PaymentSystemAppV1#PaymentSystemServiceEjbV1.jar#PaymentServiceBean, null)". Exception data: <openjpa-1.0.3-SNAPSHOT-r420667:649224 fatal user error> org.apache.openjpa.persistence.InvalidStateException: You have closed the EntityManager, though the persistence context will remain active until the current transaction commits.
at org.apache.openjpa.persistence.EntityManagerImpl.assertNotCloseInvoked(EntityManagerImpl.java:1068)
Our persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="PaymentSystemEntityV1" transaction-type="JTA">
<jta-data-source>paymentDsSrv</jta-data-source>
<mapping-file>META-INF/namedQueries.xml</mapping-file>
/* entities */
<properties>
<property name="openjpa.TransactionMode" value="managed" />
<property name="openjpa.ConnectionFactoryMode" value="managed" />
<property name="openjpa.jdbc.DBDictionary" value="db2" />
<property name="openjpa.jdbc.Schema" value="PAYMENT"/>
<property name="openjpa.Log" value="DefaultLevel=INFO, Runtime=INFO, Tool=INFO, SQL=TRACE"/>
</properties>
</persistence-unit>
Spring Context:
<bean id="dbsJpaDao" parent="daoBase" class="com.kavuntek.dds.dao.impl.DbsJpaDaoImpl" />
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<bean id="entityManagerFactory" class="javax.persistence.Persistence"
factory-method="createEntityManagerFactory" >
<constructor-arg type="java.lang.String" value="PaymentSystemEntityV1"/>
</bean>
DAO:
public class DbsJpaDaoImpl implements IDbsJpaDao{
#PersistenceContext
private EntityManager entityManager;
public List<DbsLimit> subscriberLimitInquiry(){
...
return entityManager.createQuery(queryString);
}
EJB3.0 Service Bean:
#Stateless
#TransactionAttribute(TransactionAttributeType.REQUIRED)
#TransactionManagement(value = TransactionManagementType.CONTAINER)
#Interceptors(SpringBeanAutowiringInterceptor.class)
#Local(IDDSServiceV1.class)
public class DDSServiceBean iplements IDDSServiceV1{
#Autowired
private IDDSService ddsService;
public List<DbsInvoice> subscriberLimitInquiry()
...
I tried also spring LocalContainerEntityManagerFactory with these parameters:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" >
<property name="persistenceUnitName" value="PaymentSystemEntityV1"/>
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter"/>
</property>
</bean>
Because transactions are not Spring managed, using WebSphereUowTransactionManager matters?
Nothing changed.
<bean id="transactionManager"
class="org.springframework.transaction.jta.WebSphereUowTransactionManager"/>
Any opinions?
Thanks.
P.S. When i call entityManager.getTransaction() in DAO i get:
Exception data: java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead