Monday, April 13, 2009

Java Transaction Attributes explained in detail

Must read article before deciding on transaction attributes while configuring spring transaction manager transaction attributes for different service methods for your application

I had to search a lot to find a good article explaining in detail about various transaction attributes in java transaction management. At last I found the below piece of information from ibm website.
Full credit to the owner of the article. click here to view the entire article. Corresponding section copy pasted below.

Transaction attributes

In addition to the rollback directives, you must also specify the transaction attribute, which defines how the transaction should behave. The Java platform supports six types of transaction attributes, regardless of whether you are using EJB or the Spring Framework:

  • Required
  • Mandatory
  • RequiresNew
  • Supports
  • NotSupported
  • Never

In describing each of these transaction attributes, I'll use a fictitious method named methodA() that the transaction attribute is being applied to.

If the Required transaction attribute is specified for methodA() and methodA() is invoked under the scope of an existing transaction, the existing transaction scope will be used. Otherwise, methodA() will start a new transaction. If the transaction is started by methodA(), then it must also be terminated (committed or rolled back) by methodA(). This is the most commonly used transaction attribute and is the default for both EJB 3.0 and Spring. Unfortunately, in many cases, it is used incorrectly, resulting in data-integrity and consistency issues. For each of the transaction strategies I'll cover in subsequent articles in this series, I'll discuss use of this transaction attribute in more detail.

If the Mandatory transaction attribute is specified for methodA() and methodA() is invoked under an existing transaction's scope, the existing transaction scope will be used. However, if methodA() is invoked without a transaction context, then aTransactionRequiredException will be thrown, indicating that a transaction must be present before methodA() is invoked. This transaction attribute is used in the Client Orchestration transaction strategy described in this article's next section.

The RequiresNew transaction attribute is an interesting one. More often than not, I find this attribute misused or misunderstood. If the RequiresNew transaction attribute is specified for methodA() and methodA() is invoked with or without a transaction context, a new transaction will always be started (and terminated) by methodA(). This means that if methodA() is invoked within the context of another transaction (called Transaction1 for example), Transaction1 will be suspended and a new transaction (called Transaction2) will be started. Once methodA() ends, Transaction2 is then either committed or rolled back, and Transaction1 resumes. This clearly violates the ACID (atomicity, consistency, isolation, durability) properties of a transaction (specifically the atomicity property). In other words, all database updates are no longer contained within a single unit of work. If Transaction1 were to be rolled back, the changes committed by Transaction2 remain committed. If that's the case, what good is this transaction attribute? As indicated in the first article in this series, this transaction attribute should only be used for database operations (such as auditing or logging) that are independent of the underlying transaction (in this caseTransaction1).

The Supports transaction attribute is another one that I find most developers don't fully understand or appreciate. If theSupports transaction attribute is specified for methodA() and methodA() is invoked within the scope of an existing transaction, methodA() will execute under the scope of that transaction. However, if methodA() is invoked without a transaction context, then no transaction will be started. This attribute is primarily used for read-only operations to the database. If that's the case, why not specify the NotSupported transaction attribute (described in the next paragraph) instead? After all, that attribute guarantees that the method will run without a transaction. The answer is simple. Invoking the query operation in the context of an existing transaction will cause data to be read from the database transaction log (in other words, updated data), whereas running without a transaction scope will case the query to read unchanged data from the table. For example, if you were to insert a new trade order into the TRADE table and subsequently (in the same transaction) retrieve a list of all trade orders, the uncommitted trade would appear in the list. However, if you were to use something like the NotSupported transaction attribute instead, it would cause the database query to read from the table, not the transaction log. Therefore, in the previous example, you would not see the uncommitted trade. This is not necessarily a bad thing; it depends on your use case and business logic.

The NotSupported transaction attribute specifies that the method being called will not use or start a transaction, regardless if one is present. If the NotSupported transaction attribute is specified for methodA() and methodA() is invoked in context of a transaction, that transaction is suspended until methodA() ends. When methodA() ends, the original transaction is then resumed. There are only a few use cases for this transaction attribute, and they primarily involve database stored procedures. If you try to invoke a database stored procedure within the scope of an existing transaction context and the database stored procedure contains a BEGIN TRANS or, in the case of Sybase, runs in unchained mode, an exception will be thrown indicating that a new transaction cannot be started if one already exists. (In other words, nested transactions are not supported.) Almost all containers use the Java Transaction Service (JTS) as the default transaction implementation for JTA. It's JTS — not the Java platform per se — that doesn't support nested transactions. If you cannot change the database stored procedure, you can use the NotSupported attribute to suspend the existing transaction context to avoid this fatal exception. The impact, however, is that you no longer have atomic updates to the database in the same LUW. It is a trade-off, but it can get you out of a difficult situation quickly.

The Never transaction attribute is perhaps the most interesting of all. It behaves the same as the NotSupported transaction attribute with one important difference: if a transaction context exists when a method is called using the Never transaction attribute, an exception is thrown indicating that a transaction is not allowed when you invoke that method. The only use case I have been able to come up with for this transaction attribute is for testing. It provides a quick and easy way of verifying that a transaction exists when you invoke a particular method. If you use the Never transaction attribute and receive an exception when invoking the method in question, you know a transaction was present. If the method is allowed to execute, you know a transaction was not present. This is a great way of guaranteeing that your transaction strategy is solid.

No comments:

Post a Comment