In our new project we would like to achieve transactions that involve jpa (mysql) and a message bus (rabbitmq)
We started building our infrastructure with spring data using mysql and rabbitmq (via spring amqp module). Since rabbitMq is not XA-transactional we configured the neo4j chainedTransactionManager as our main transactionManager. This manager takes as argument the jpa txManager and the rabbitTransactionManager.
Now, I do get the ability to annotate a service with #Transacitonal and use both the jpa and rabbit inside it. If I throw an exception within the service then none of the actions actually occur.
Here are my questions:
Is this configuration really gives me an atomic transaction?
I've heard that the chained tx manager is not using a 2 phase commit but a "best effort", is this best effort less reliable? if so how?
What the ChainedTransactionManager does is basically start and commit transactions in reverse order. So if you have a JpaTransactionManager and a RabbitTransactionManager and configured it like so.
#Bean
public PlatformTransactionManager transactionManager() {
return new ChainedTransactionManager(rabbitTransactionManager(), jpaTransactionManager());
}
Now if tha JPA commit succeeds but your commit to rabbitMQ fails your database changes will still be persisted as those are already committed.
To answer your first question it doesn't give you a real atomic transaction, everything that has been committed prior to the occurence of the Exception (on committing) will remain committed.
See http://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/transaction/ChainedTransactionManager.html
Related
Please explain me if I understood correctly Spring documentation.
Spring docs states: https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#jms-tx
(...)When you use the JmsTemplate in an unmanaged environment, you can specify these values (transaction and acknowledgment modes) through the use of the properties sessionTransacted and sessionAcknowledgeMode.
When you use a PlatformTransactionManager with JmsTemplate, the template is always given a transactional JMS Session.(..)
(BTW, that is true - session is transactional)
Javadoc states : https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/jms/core/JmsTemplate.html
Default settings for JMS Sessions are "not transacted" and "auto-acknowledge". As defined by the Java EE specification, the transaction and acknowledgement parameters are ignored when a JMS Session is created inside an active transaction, no matter if a JTA transaction or a Spring-managed transaction.
I understood that if transaction is active, JMS Template session transaction settings are ignored - that is true - and the session should participate active transaction - that is not true.
I debug why it is not true and I found: https://github.com/spring-projects/spring-framework/blame/master/spring-jms/src/main/java/org/springframework/jms/connection/ConnectionFactoryUtils.java#L353
if (resourceHolderToUse != resourceHolder) {
TransactionSynchronizationManager.registerSynchronization(
new JmsResourceSynchronization(resourceHolderToUse, connectionFactory,
resourceFactory.isSynchedLocalTransactionAllowed()));
resourceHolderToUse.setSynchronizedWithTransaction(true);
TransactionSynchronizationManager.bindResource(connectionFactory, resourceHolderToUse);
}
The line resourceHolderToUse.setSynchronizedWithTransaction(true) is align the documentation.
The issue here: resourceFactory.isSynchedLocalTransactionAllowed()
Because resourceFactory is org.springframework.jms.core.JmsTemplate.JmsTemplateResourceFactory#isSynchedLocalTransactionAllowed which points to JmsTemplate#sessionTransacted.
Conclusion:
According to documentation, if transaction is active, JmsTemplate#sessionTransacted should be ignored. But it is not true - although session is transactional, cannot not participate in commit.
JmsTemplate#sessionTransacted is finally mapped to ConnectionFactoryUtils.JmsResourceSynchronization#transacted and default=false prevents commit being called at the end of transaction (JmsResourceSynchronization "thinks" that it does not participate transaction)
Do I understand documentation right and there is really bug here?
Guided by M. Deinum, I made more experiments and it seems I wrongly understood term Spring-managed transaction
I simply thought that Spring managed transaction is started by platformTransactionManager. But:
If platformTransactionManager is JtaTransactionManager and transaction is started, it IS Spring managed transaction; JMS template attribute sessionTransacted is ignored and JMS template is part of transaction
if platformTransactionManager is DataSourceTransactionManager or JpaTransactionManager then
if sessionTransacted is false, JMS template is not in transaction
if sessionTransacted is true, JMS template is synchronized with transaction: after callback/rollback on JDBC/JPA transaction correspondent commit/rollback is called on JMS transaction
what is the difference between TransactionManagementType.CONTAINER and TransactionManagementType.BEAN
as Im using TransactionManagementType.CONTAINER in all of my EJBs and when ever the multiple instances of database is used, It throws an error which gets resolved if i change it to TransactionManagementType.BEAN
I want to know what are the advantages and disadvantages and how it gets effected if I change it to TransactionManagementType.BEAN
ERROR:
Error updating database. Cause: java.sql.SQLException: javax.resource.ResourceException:
IJ000457: Unchecked throwable in managedConnectionReconnected() cl=org.jboss.jca.core.
connectionmanager.listener.TxConnectionListener#680f2be0[state=NORMAL managed
connection=org.jboss.jca.adapters.jdbc.local.LocalManagedConnection#7ba33a94 connection
handles=0 lastReturned=1495691675021 lastValidated=1495690817487
lastCheckedOut=1495691675018 trackByTx=false pool=org.jboss.jca.core.connectionmanager.
pool.strategy.OnePool#efd42c4 mcp=SemaphoreConcurrentLinkedQueueManagedConnectionPool
#71656eec[pool=FAQuery] xaResource=LocalXAResourceImpl#4c786e85
[connectionListener=680f2be0 connectionManager=5c3b98bc warned=false
currentXid=null productName=Oracle productVersion=Oracle Database 12c
Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options
jndiName=java:/FAQuery] txSync=null]
TransactionManagementType.CONTAINER
You let the container itself manage transactions(container will commit and rollback). You can control behavior of your transactions (more precisely transaction propagation) by annotating methods with #TransactionManagementAttribute and specifying one of the attributes from TransactionAttribute Types.
TransactionManagementType.BEAN
You have to do transaction demarcation (start, commit, rollback) explicitly yourself, by obtaining UserTransaction interface.
#Resource
UserTransaction ut;
public void method(){
ut.begin();
... // your business logic here
ut.commit(); // or ut.rollback();
}
Note that you have to either commit and rollback before you exit the same method which stated the transaction for Stateless and Message Driven Beans, but it is not required for Stateful bean.
Regarding your question, advantage of BMT is that scope of the transaction can be less than scope of the method itself, i.e explicit control of the transaction.
You would most probably use CMT, BMT is required only in some narrow corner cases to support specific business logic.
Another advantage or use case of BMT is if you need to use Extended Persistence Context Type, which can be supported in BMT with Stateful Session Beans.
Regarding your specific problem, without seeing any bean code or error messages, this is probably what is happening: if you have more databases then each database and its corresponding driver must be able to join an existing transaction, otherwise you will get a specific detailed error.
If you use TransactionManagementType.BEAN the bean is required to start a brand new transaction. Which means you are not joining an existing transaction, and each database operations begin and commit independently from each others.
You can achieve the same effect by leaving TransactionManagementType.CONTAINER and annotating your method with REQUIRES_NEW, provide of course you are calling each EJB trough the corresponding proxy/interface.
So it is not correct to put it like BEAN vs CONTAINER, but rather you have to made some design choice and annotate your methods accordingly.
As requested for a method marked with one of the following:
REQUIRES_NEW existing transactions gets suspended, and the method runs under a brand new transaction
REQUIRED is the default behavior, if a transaction exists it is reused by the method, otherwise gets created and the method runs in it
I have a method that get an invoice and it creates XML and send that XML to a JMS queue and then save the invoice to DB with updated status like 'invoiced'. Below is pseudo code that involves Spring and Hibernate. My question is: Is the failure in hibernate save rollsback Jms sending.or if JMS send failed, how can I roll back saving invoice status? is this comes under distributed transaction management. What are the transactional cases involved here. Thanks.
#Transactional(propagation=Propagation.Required)
void processInvoices(invoice ){
String xml = createXML(invoice);
messageService.sendInvoice(xml );
invoice.setStatus("invoiced");
save(invoice);
}
As per my knowledge and what I understand from your question you want to synchronize hibernate and JMS transaction, For doing this you will need to use JTA to manage transactions across the the both Hibernate and JMS
Read More # Spring synchronising Hibernate and JMS transactions
I want to test the integration of Spring and Activiti, then I stuck with confusing problem. I have a workflow with 2 service task (using jpa repository saveAndFlush method to update database) A and B
In the service A, I actively throw a new Exception , then the transaction rollbacks, and the flow stops. Well, it's okay.
However, how can I rollback the service A only and the flow continue to service B?
Because if service A throws Exception, the flow will be stopped, and if Exception is caught ( then the flow continues), service A will not rollback.
I use JPA Repository to automatically handle transaction, so change to manual mode will take a lot of efforts now.
Probably you need a new transaction for every service in the flow and catch all exception.
Put a layer between your service tasks A,B and your process, let's make its name TransactionService. This service should trigger your service methods. Also those service methods should use new transactions for their operations(you can use #Transactional annotation). In TransactionService don't do anything, just trigger them and wrap them in try catch blocks.
As a result of them you can catch the exception and make it flow to the next task and doesn't care about rollback because after an exception it will be rolled back automatically.
I have mybatis 3.0.4 with mybatis-spring integration 1.0.1 deployed within Fuse (OSGi). I've created a basic database within SQLServer 2008. In Spring I've configured a TransactionAwareDataSourceProxy data source and a DataSourceTransactionManager transaction manager.
Now I've created my own bundle to be deployed within Fuse which inserts some rows into the database. I've told the bundle to use the configured data source and transaction manager. The method which carries out the logic looks like this:
#Transactional(propagation=Propagation.REQUIRED)
public void go(RecsCashContext context) throws ActionException {
When this method throws an exception I can follow Spring through seeing the expected behaviour triggered. This leads me to Springs JtaTransactionManager and doRollBack(..).
So everything looks promising, except that when I look at the database, sure enough it's in an unstable state as previous inserts have not been roll back.
I'm at a loss on this one and I'm struggling to find any information online. Any thoughts?
What kind of exception is being thrown? Unless you tell Spring to explicitly rollback when a particular exception is thrown, it will proceed. By default, Spring's transaction handling only rolls back when an unchecked exception (e.g. RuntimeException) is thrown. In your case, if you're expecting the rollback to occur when ActionException occurs, you're out of luck unless you make the following modification:
#Transactional(rollbackFor={ActionException.class})
public void go(RecsCashContext context) throws ActionException {
More details are in here, specifically in section 10.5.6.1, #Transactional settings
As it turns out Fuse (servicemix) already exposes a transaction manager via an OSGi service within bundle org.apache.aries.transaction.manager_0.2.0.incubating [49]. As a result when I was looking up the transaction manager service, the one exposed by bundle 49 got picked up first.
This was resolved by clearly specifying the transaction manager I was interested in. At the moment I am doing this using the bean-name propery:
<osgi:reference id="transactionManager" bean-name="transactionManager" interface="org.springframework.transaction.PlatformTransactionManager" />
Though this could also be done by using a filter, but preferably we'll just make use of the transaction manager service that's already being expose as opposed to providing our own.