Spring Global transaction vs Local transaction - java

While reading through Spring transaction documentation I see that it supports both Global transactions and Local transactions.
In simple terms what is global transaction and what is local transaction?
What are the advantages of one over the other? What are the appropriate uses of them?
If I use the following configuration – does it mean it is a local transaction?
<tx:annotation-driven transaction-manager="transManager" />
<bean id="transManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>
I tried searching both in Google and Stackoverflow, but did not get any resources explaining the same in simple terms.

Actually there are plenty of resources answering your first two questions, for example Spring Documentation explains what local and global transaction is and depicts their differences in chapter 9.2 Motivation. In few words:
Global Transaction is an application server managed transaction, allowing to work with different transactional resources (this might be two different database, database and message queue, etc)
Local Transaction is resource specific transaction (for example Oracle Transactions) and application server has nothing to do with them.
(the same chapter explains the pros and cons of each of them very well and much better then I could explain, so I suggest you to give a closer look)
Answering your later question. The documentation says that JpaTransactionManager is capable for processing global transactions, so by looking at the piece of presented code it's hard to say if it's local or global transaction. The same documentation says that local single-resource transaction DataSourceTransactionManager should be used instead.

Related

working with JTATransactionManager for transactions?

I am using spring3 and Hibernate4 with Tomcat7.
I have to use JTATransactionManager and i have below configuration.
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="userTransactionName" value="java:comp/UserTransaction"></property>
</bean>
In above configuration where is java:comp/UserTransaction defined?
Thanks!
It is a JNDI reference to container-supplied user transaction object.
It is not user configurable as such (as in you cannot change the value yourself). The value depends on the EE container you use.
As to what user transaction object really is, see Wikipedia:
UserTransaction interface
The javax.transaction.UserTransaction interface provides the
application the ability to control transaction boundaries
programmatically. This interface may be used by Java client programs
or EJB beans.
The UserTransaction.begin() method starts a global transaction and
associates the transaction with the calling thread. The
transaction-to-thread association is managed transparently by the
Transaction Manager.
Support for nested transactions is not required. The
UserTransaction.begin method throws the NotSupportedException when the
calling thread is already associated with a transaction and the
transaction manager implementation does not support nested
transactions.
Transaction context propagation between application programs is
provided by the underlying transaction manager implementations on the
client and server machines. The transaction context format used for
propagation is protocol dependent and must be negotiated between the
client and server hosts. For example, if the transaction manager is an
implementation of the JTS specification, it will use the transaction
context propagation format as specified in the CORBA OTS 1.1
specification. Transaction propagation is transparent to application
programs..
JTA and associated with it XA transactions are tricky things to implement and support. As #js-nizet said only JEE Application servers have their own transaction managers implementation working out of the box. For lightweight web server like Tomcat or Jetty you have to provide an external implementation and to configure the Spring to work with it. There are a lot of choices so it is up to you. I can recommend you Jboss' Narayana, but it is really up to you. Since it is not so straight-forward to have this running I would recommend you the following blog post which describes everything in a great detail - Configuring Spring and JTA without full Java EE.
Here's another post on how to configure Narayan with Spring and Jetty.

Transaction-type for local postgres tool?

I have a local application (no JEE server) that shall use postgres at the end.
I'd like to chose Hibernate as my database framework. I'm now creating the persistence.xml, and wonder which transaction-type I should chose: JTA or RESOURCE_LOCAL, or none?
<persistence-unit name="travelport" transaction-type="JTA">
Further I'd like to use the Hibernate EntityManager in my application. Can I have my application manage the transaction itself somehow (any framework)? Or do I always have to open, commit and close the transactions myself when not using an application server?
You really only need the JTA transaction type if you're running in an EE environment, so definitely choose RESOURCE_LOCAL.
As for transaction management, have a look at Spring Transaction Management - I won't repeat the good examples in that link here, but feel free to post follow-up questions if needs be :-)
And don't forget DB pooling as well (DBCP, C3P0 etc).
Cheers,
For a SE application, you should use RESOURCE_LOCAL and manage the transaction by yourself.
Automatic transaction management would require the beans/services to have a managed lifecycle and a possibility to plug in into that lifecycle.
I am not aware of a readymade lifecycle framework for Java (Spring is a good option for servlet containers, but be aware of all the goods it brings to the table in addition to the bean lifecycle).

Spring Transaction Synchronization of JDBC and JMS

I have a spring web app running on jboss that is currently configured to use the HibernateTransactionManager for db transactions and the JmsTransactionManager for jms. For jms we use Camel and ActiveMQ, our database is DB2. Within a transaction I need to write a number of records to the database and send two asynchronous jms messages. The jms messages are event notifications and I only want them to be sent if the database transaction commits.
I am willing to accept the risk of the communication with the broker failing after the jdbc transaction has already committed (and thus no messages sent but db committed) so I do not think I need proper XA.
I believe that what I need is "best efforts" transaction management using spring transaction synchronization.
The spring documentation sort of hints at the fact that spring will synchronize the two transactions and commit the jms transaction only after the jdbc transaction has been committed - but I don't think it is very clear. The spring documentation here http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html#tx-resource-synchronization doesn't go into enough detail about how it works.
I have found a couple of other sources that say spring will do what I want including some javadoc below, and I have written some integration tests that also show it.
http://static.springsource.org/spring/docs/3.0.x/api/org/springframework/jms/support/JmsAccessor.html#setSessionTransacted%28boolean%29 The javadoc on setSessionTransacted here sounds like exactly what I want.
From what I have seen I think creating the Camel JmsConfiguration with transacted set to true like this is enough:
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="pooledConnectionFactory"/>
<property name="transacted" value="true"/>
<property name="concurrentConsumers" value="10"/>
</bean>
However I need to convince someone I work with who is a bit skeptical and thinks that my integration test only works because of a poorly documented side effect rather than a intentional spring feature.
So my question is - Am I correct that spring can be relied upon to synchronize the transactions and always commit the jms transaction after the jdbc transaction or is that not something that I should rely on, and could you point me at any official documentation that says that clearly? And I guess in general is this a good approach to take or should we be managing these transactions in a different way?
This article might be of help Distributed transactions in Spring, with and without XA. I don't think it covers your case specifically - sending message + updating database.
Official Spring Boot repository contain JTA examples that combine JMS with JDBC based on Atomikos, Bitronix or Java EE server JBoss WildFly.
Additionally I also created few examples that are located in my Github repository. This contains also non-Spring Boot (pure Spring) example.
If you are using Local transactions
And the usecase is save to database and then send to jms
Then there could be three cases :
Exception just after receiving(before DB and JMS)
No problem everything will be rolledback
After saving to DB , we have exception
If there is an insert operation,there will be mutiple rows in DB due to retries.With each retry , an insert will be done.And for JMS , message will go to DeadLetterQueue
After saving to DB and sending to JMS , we have an exception
If there is an insert operation,there will be mutiple rows in DB due to retries.With each retry , an insert will be done.And for JMS , message will go to DeadLetterQueue
Now you dont want to use XA, so the solutions could be
1)Check If(message.getJmsRedelivered() {…}
If not , process it
If its redelivered , check if you processed it already
Check if the data is in database based on details in message
Note that re-deliveries are rare so , this check is also rare and there is no overhead
2)If your method is idempotent , then you dont need this check
And regarding XA , XA guarantees that message is delivered only once
And synchronize the transaction across multiple resources
But with XA , you have overhead
So if you can manage without XA , it is preferable

"Local transaction already has 1 non-XA Resource: cannot add more resources" error

After reading previous questions about this error, it seems like all of them conclude that you need to enable XA on all of the data sources. But:
What if I don't want a distributed
transaction? What would I do if I want to
start transactions on two different
databases at the same time, but
commit the transaction on one database
and roll back the transaction on
the other?
I'm wondering how my code
actually initiated a distributed
transaction. It looks to me like I'm
starting completely separate
transactions on each of the
databases.
Info about the application:
The application is an EJB running on a Sun Java Application Server 9.1
I use something like the following spring context to set up the hibernate session factories:
<bean id="dbADatasource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/dbA"/>
</bean>
<bean id="dbASessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dbADatasource" />
<property name="hibernateProperties">
hibernate.dialect=org.hibernate.dialect.Oracle9Dialect
hibernate.default_schema=schemaA
</property>
<property name="mappingResources">
[mapping resources...]
</property>
</bean>
<bean id="dbBDatasource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/dbB"/>
</bean>
<bean id="dbBSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dbBDatasource" />
<property name="hibernateProperties">
hibernate.dialect=org.hibernate.dialect.Oracle9Dialect
hibernate.default_schema=schemaB
</property>
<property name="mappingResources">
[mapping resources...]
</property>
</bean>
Both of the JNDI resources are javax.sql.ConnectionPoolDatasoure's. They actually both point to the same connection pool, but we have two different JNDI resources because there's the possibility that the two, completely separate, groups of tables will move to different databases in the future.
Then in code, I do:
sessionA = dbASessionFactory.openSession();
sessionB = dbBSessionFactory.openSession();
sessionA.beginTransaction();
sessionB.beginTransaction();
The sessionB.beginTransaction() line produces the error in the title of this post - sometimes. I ran the app on two different sun application servers. On one runs it fine, the other throws the error. I don't see any difference in how the two servers are configured although they do connect to different, but equivalent databases.
So the question is
Why doesn't the above code start
completely independent transactions?
How can I force it to start
independent transactions rather than
a distributed transaction?
What configuration could cause the difference in
behavior between the two application
servers?
Thanks.
P.S. the stack trace is:
Local transaction already has 1 non-XA Resource: cannot add more resources.
at com.sun.enterprise.distributedtx.J2EETransactionManagerOpt.enlistResource(J2EETransactionManagerOpt.java:124)
at com.sun.enterprise.resource.ResourceManagerImpl.registerResource(ResourceManagerImpl.java:144)
at com.sun.enterprise.resource.ResourceManagerImpl.enlistResource(ResourceManagerImpl.java:102)
at com.sun.enterprise.resource.PoolManagerImpl.getResource(PoolManagerImpl.java:216)
at com.sun.enterprise.connectors.ConnectionManagerImpl.internalGetConnection(ConnectionManagerImpl.java:327)
at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:189)
at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:165)
at com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:158)
at com.sun.gjc.spi.base.DataSource.getConnection(DataSource.java:108)
at org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider.getConnection(LocalDataSourceConnectionProvider.java:82)
at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:446)
at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:167)
at org.hibernate.jdbc.JDBCContext.connection(JDBCContext.java:142)
at org.hibernate.transaction.JDBCTransaction.begin(JDBCTransaction.java:85)
at org.hibernate.impl.SessionImpl.beginTransaction(SessionImpl.java:1354)
at [application code ...]
1 Why doesn't the above code start completely independent transactions?
The app. server manages the transaction for you which can, if necessary, be a distributed transaction. It enlists all the participants automatically. When there's only one participant, you don't notice any difference with a plain JDBC transaction, but if there are more than one, a distributed transaction is really needed, hence the error.
2 How can I force it to start independent transactions rather than a
distributed transaction?
You can configure the datasource to be XA or Local. The transactional behavior of Spring/Hibernate can also be configured to use either regular JDBC transactions or delegate the management of transactions to the JTA distributed transaction manager.
I suggest you switch the datasource to non-XA and try to configure Spring/Hibernate to use the JDBC transactions. You should find the relevant information in the documentation, here what I suspect is the line to change:
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager" />
This should essentially means that you are not using the app. server distributed transaction manager.
3 What configuration could cause the difference in behavior between the
two application servers?
If you have really exactly the same app and configuration, this means that in one case only one participant is enlisted in the dist. transaction, while there are two in the 2nd case. One participant corresponds to one physical connection to a database usually. Could it be that in one case, you use two schema on two different databases, while in the 2nd case you use two schema on the same physical database? A more probable explanation would be that the datasource were configured differently on the two app. server.
PS: If you use JTA distributed transactions, you should use UserTransaction.{begin,commit,rollback} rather than their equivalent on the Session.
After reading previous questions about this error, it seems like all of them conclude that you need to enable XA on all of the data sources.
No, not all, all except one (as the exception is saying) if your application server supports Logging Last Resource (LLR) optimization (which allows to enlist one non-XA resource in a global transaction).
Why doesn't the above code start completely independent transactions?
Because you aren't. When using beginTransaction() behind EJB Session Beans, Hibernate will join the JTA transaction (refer to the documentation for full details). So the first call just works but the second call means enlisting another transactional resource in the current transaction. And since none of your resources are XA, you get an exception.
How can I force it to start independent transactions rather than a distributed transaction?
See #ewernli answer.
What configuration could cause the difference in behavior between the two application servers?
No idea. Maybe one of them is using at least one XA datasource.

when using #transactional do i need to use jpatemplate/hibernatetemplate?

when using #transactional do i need to use jpatemplate/hibernatetemplate ?
No, you don't. Spring has a built-in transaction manager that can be used for simple transactions, e.g. if you don't need to track transactions across more than one DataSource. The configuration should be as simple as this:
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
Where the bean named "dataSource" is some DataSource bean configured elsewhere in your XML file.
However if you're using JPA or Hibernate, it would be a good idea to use the JPATransactionManager or HibernateTransactionManager, respectively.
If you really wanted to you could also use JTA, which is Sun's standard transaction implementation. I think the spring class is called JTATransactionManager.
Using transaction managers other than Spring's out-of-the-box one (the one defined in the XML config above) will give you the ability to use transactions across multiple DataSources.
The answer depends on the what version of Hibernate you are using. With later versions the simple answer is no you don't need the templates. See here for a comprehensive discussion:
http://blog.springsource.com/2007/06/26/so-should-you-still-use-springs-hibernatetemplate-andor-jpatemplate/
I came across an article that explains the process of implementing TxManager using #Transactional in depth. If you are interested, you can check this article here. I tried and this works!

Categories