2. Configure Transactions without XML
Spring 3.1 introduces the @EnableTransactionManagement annotation to be used in on @Configuration classes and enable transactional support:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19With transactions configured, a bean can now be annotated with @Transactional either at the class or method level:
The annotation supports further configuration as well:
Note that – by default, rollback happens for runtime, unchecked exceptions only. The checked exception does not trigger a rollback of the transaction; the behavior can, of course, be configured with the rollbackFor and noRollbackFor annotation parameters.
| @Configuration @EnableTransactionManagement public class PersistenceJPAConfig{ @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(){ //... } @Bean public PlatformTransactionManager transactionManager(){ JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory( entityManagerFactoryBean().getObject() ); return transactionManager; } }
|
ACID
A:Atomic: "Either all or none"
C: Consistent :"Transaction complete: system back to normal"
I: Isolated :One transaction shall not impact other
D:Durable : Changes of transaction are persisted in permanent storage
TRANSACTION ISOLATION LEVEL
HOW THE CHANGES MADE TO SOME DATA REPOSITARY BY ONE TRANSACTION AFFECT OTHER SIMULTANEOUS CONCURRENT TRANSACTIONS,HOW AND WHEN THAT DATA BECOMES AVIALABLE TO OTHERS
@TRANSACTIONAL
@Autowired
private BankAccountDAO bankAccountDAO;
@Transactional(isolation=isolation.READ_COMMITED)
public void transfer()
__________________________________________________________
What is dirty read?
Non repeatable read
PHANTOM READ
isolation.READ_UNCOMMITED: Allows to read uncommited changes
isolation.READ_COMMITED Allows to read commited transactions
isolation.REPEATABLE_READ Allows multiple to read commited transactions
isolation.READ_SERIALIZABLE :read|write|locks : slow
PROPAGATION
MANDATORY
Support a current transaction, throw an exception if none exists.
|
NESTED
Execute within a nested transaction if a current transaction exists, behave like PROPAGATION_REQUIRED else.
|
NEVER
Execute non-transactionally, throw an exception if a transaction exists.
|
NOT_SUPPORTED
Execute non-transactionally, suspend the current transaction if one exists.
|
REQUIRED
Support a current transaction, create a new one if none exists.
|
REQUIRES_NEW
Create a new transaction, and suspend the current transaction if one exists.
|
SUPPORTS
Support a current transaction, execute non-transactionally if none exists.
|
ACID properties
ACID is an acronym that stands for atomic, consistent, isolated and durable. An operation is a transaction if and only if it has these four characteristics, which I’ll describe briefly:
- Atomic: all-or-nothing property. Even though a transaction comprises multiple operations, it is completed as a single logical unit of work. Either the whole thing succeeds or none of it does.
- Consistent: We want our “transactional resource” (which in most cases means our database) to be consistent with reality. So for example if I have 4,132 widgets in stock after I sell you five of them, then I want the database to say that I have 4,132 widgets in stock after I run a
sell(you, 5, widget)
transaction. The consistency property means that after a transaction completes, the database (or whatever transactional resource we’re using) matches up with the real world. - Isolated: . The isolation property means that when you run a transaction, it achieves its results without interference from other transactions. That doesn’t mean that the transactions can’t run concurrently—it just means that the transactions shouldn’t corrupt each other in the process. In practice it’s nontrivial to strike the right balance between concurrency and isolation; transactions however exhibit some level of isolation, and well-designed transactions exhibit the “right” amount of isolation.
- Durable: This just means that after a transaction has ended, its results are made persistent. Probably they would have called this property “persistent” instead of “durable”, but “ACIP” is not as cool as “ACID”.
Defining individual transactions
Defining a transaction involves picking a chunk of code (maybe a method, maybe a set of methods, maybe a block of code inside a method) and setting values for the following five parameters:
Propagation behavior:
- Specify its “boundaries”: where does the transaction start and where does it end? In Spring (and also in EJB), the boundaries of a transaction may or may not coincide with the boundaries of a Java method. In one respect this is not unlike using the
synchronized
keyword: if one synchronized method calls another on the same class, then the protected scope includes both methods, not just one, and so the boundaries do not coincide with a single method. But the difference is that with transactions you have a lot more flexibility as far as defining the boundaries. Certainly it is possible to enter a transaction starting from one method and then include additional method calls within the scope of that initial transaction. But you can do other things too, such as declare that calls to other methods open up new transactions, or that a given method must always run within the scope of an existing transaction, etc. I won’t go over all the options here but there are seven and you can see them here: transaction propagation options. ProbablyPROPAGATION_REQUIRED
is the most typical.
- Isolation level: I mentioned above that in practice concurrency trades against isolation. (Once again there’s an analogy with threads, incidentally.) You can specify the level of isolation you need for a given transaction; the general rule of thumb is assign the weakest isolation level you can safely get away with so as to maximize concurrency. Again I won’t go into the details but you can find them here: transaction isolation levels. The most typical cases are
ISOLATION_READ_COMMITTED
andISOLATION_REPEATABLE_READ
. TheISOLATION_READ_UNCOMMITTED
is so weak as to be almost useless in practice, andISOLATION_SERIALIZABLE
is so strong that you don’t want to use it unless you really, really need the safety it provides: it’s a concurrency-killer.
- Timeout: I’m currently reading a great book on software
- development called Release It!: Design and Deploy Production-Ready Software, by Michael T. Nygard. In a nutshell this book makes the case that designing software against a functional requirements document isn’t (at all) the same thing as designing software for the data center, and to do the latter you need to assume that serious bugs will infiltrate your production releases and design your software to deal with that reality. One of the key insights is that problems occur primarily at integration points, and one of the strategies for dealing with that is to use timeouts. Transaction timeouts allow the calling application to give up if the database hasn’t completed the transaction within a specifiable interval of time.
- Read-only: This flag indicates whether the transaction will be, well, read-only. If so, you can flag it as such and the underlying database or other resource can apply optimizations based on that fact.
- Rollback behavior: By default, both Spring and EJB roll back a transaction (i.e., cancel it without applying any of the changes) when runtime exceptions, but not when checked exceptions occur. You can modify that behavior.
____________________________________________________________________
Effective Spring Transaction Management
Learn all about transaction management using Spring, and explore what transaction management is, how to effectively tackle this in spring, and various tips.
The State of API Integration 2018: Get Cloud Elements’ report for the most comprehensive breakdown of the API integration industry’s past, present, and future.
Introduction:
- Most of the time developers give the least importance to transaction management and as a result lots of code has to be reworked later or developer implements transaction management without knowing how it actually works or what aspect needs to be used in their scenario.
- An important aspect of transaction management is defining the right transaction boundary for e.g when should a transaction start,when should it end,when data should be committed in DB and when it should be rolled back (in the case of exception).
- The most important aspect for developers is to understand how to implement transaction management in an application, in the best way. So now let's explore different ways.
Ways of Managing Transactions:
- Transaction can be managed in the following ways:
- Programmatically manage by writing custom code as below
This is the legacy way of managing transaction.
Pros:
- The scope of the transaction is very clear in the code.
Cons:
- It's repetitive and error prone.
- Any error can have a very high impact.
- A lot of boilerplate needs to be written and if you want to call another method from this method then again you need to manage it in the code.
2. Use Spring to manage transaction
Spring supports two types of transaction management:
- Programmatic transaction management : This means that you have to manage the transaction with the help of programming. That gives you extreme flexibility, but it is difficult to maintain.
- Declarative transaction management: This means you separate transaction management from the business code. You only use annotations or XML based configuration to manage the transactions.
Declarative transactions are highly recommended. If you want to know the reason for this then read below else jump directly to Declarative transaction management section if you want to implement this option.
Now, Let us discuss each approach in detail.
2.2.1 Programmatic transaction management:
The Spring Framework provides two means of programmatic transaction management.
a. Using the TransactionTemplate (Recommended by Spring Team):
Let's see how to implement this type with the help of below code (taken from Spring docs with some changes).
Please note that the code snippets are referred from Spring Docs.
Context Xml file:
Service Class:
If there is no return value, use the convenient TransactionCallbackWithoutResult class with an anonymous class as follows:
- Instances of the TransactionTemplate class are thread safe, in these instances do not maintain any conversational state.
- TransactionTemplate instances do however maintain configuration state, so while a number of classes may share a single instance of a TransactionTemplate, if a class needs to use a TransactionTemplate with different settings (for example, a different isolation level), then you need to create two distinct TransactionTemplate instances.
b. Using a PlatformTransactionManager implementation directly:
Let's see this option again with the help of code.
Now, before going to next way of managing transaction i.e Declarative Transaction Management lets see how to choose which type of transaction management to go for.
Choosing between Programmatic and Declarative Transaction Management:
- Programmatic transaction management is good only if you have a small number of transactional operations. (Most of the times, this is not the case.)
- Transaction name can be explicitly set only using Programmatic transaction management.
- Programmatic transaction management should be used when you want explicit control over managing transactions.
- On the other hand, if your application has numerous transactional operations, declarative transaction management is worthwhile.
- Declarative Transaction management keeps transaction management out of business logic, and is not difficult to configure.
2.2.2 Declarative Transaction (Usually used almost in all scenarios of any web application)
Step 1: Define a transaction manager in your spring application context xml file.
Step 2: Turn on support for transaction annotations by adding below entry to your spring application context XML file.
OR add @EnableTransactionManagement to your configuration class as below:
Spring recommends that you only annotate concrete classes (and methods of concrete classes) with @Transactional annotation as compared to annotating interfaces.
The reason for this is if you put an annotation on the Interface Level and if you are using class-based proxies (proxy-target-class="true") or the weaving-based aspect (mode="aspectj"), then the transaction settings are not recognized by the proxying and weaving infrastructure .i.e Transactional behaviour will not be applied.
Step 3: Add the @Transactional annotation to the Class (or method in a class) or Interface (or method in an interface).
Default configuration: proxy-target-class="false"
- The @Transactional annotation may be placed before an interface definition, a method on an interface, a class definition, or a public method on a class.
- If you want some methods in the class (annotated with @Transactional) to have different attributes settings like isolation or propagation level then put annotation at method level which will override class level attribute settings.
- In proxy mode (which is the default), only 'external' method calls coming in through the proxy will be intercepted. This means that 'self-invocation', i.e. a method within the target object calling some other method of the target object, won't lead to an actual transaction at runtime even if the invoked method is marked with @Transactional.
Let us now understand different @Transactional attributes.
@Transactional (isolation=Isolation.READ_COMMITTED)
- The default is Isolation.DEFAULT
- Most of the times, you will use default unless and until you have specific requirements.
- Informs the transaction (tx) manager that the following isolation level should be used for the current tx. Should be set at the point from where the tx starts because we cannot change the isolation level after starting a tx.
DEFAULT
Use the default isolation level of the underlying database.
READ_COMMITTED
A constant indicating that dirty reads are prevented; non-repeatable reads and phantom reads can occur.
READ_UNCOMMITTED
This isolation level states that a transaction may read data that is still uncommitted by other transactions.
REPEATABLE_READ
A constant indicating that dirty reads and non-repeatable reads are prevented; phantom reads can occur.
SERIALIZABLE
A constant indicating that dirty reads, non-repeatable reads, and phantom reads are prevented.
What do these Jargons dirty reads, phantom reads, or repeatable reads mean?
- Dirty Reads: Transaction 'A' writes a record. Meanwhile Transaction 'B' reads that same record before Transaction A commits. Later Transaction A decides to rollback and now we have changes in Transaction B that are inconsistent. This is a dirty read. Transaction B was running in READ_UNCOMMITTED isolation level so it was able to read Transaction A changes before a commit occurred.
- Non-Repeatable Reads: Transaction 'A' reads some record. Then Transaction 'B' writes that same record and commits. Later Transaction A reads that same record again and may get different values because Transaction B made changes to that record and committed. This is a non-repeatable read.
- Phantom Reads: Transaction 'A' reads a range of records. Meanwhile Transaction 'B' inserts a new record in the same range that Transaction A initially fetched and commits. Later Transaction A reads the same range again and will also get the record that Transaction B just inserted. This is a phantom read: a transaction fetched a range of records multiple times from the database and obtained different result sets (containing phantom records).
@Transactional(timeout=60)
Defaults to the default timeout of the underlying transaction system.
Informs the tx manager about the time duration to wait for an idle tx before a decision is taken to rollback non-responsive transactions.
@Transactional(propagation=Propagation.REQUIRED)
If not specified, the default propagational behavior is REQUIRED.
Other options are REQUIRES_NEW, MANDATORY, SUPPORTS, NOT_SUPPORTED, NEVER, and NESTED.
REQUIRED
- Indicates that the target method can not run without an active tx. If a tx has already been started before the invocation of this method, then it will continue in the same tx or a new tx would begin soon as this method is called.
REQUIRES_NEW
- Indicates that a new tx has to start every time the target method is called. If already a tx is going on, it will be suspended before starting a new one.
MANDATORY
- Indicates that the target method requires an active tx to be running. If a tx is not going on, it will fail by throwing an exception.
SUPPORTS
- Indicates that the target method can execute irrespective of a tx. If a tx is running, it will participate in the same tx. If executed without a tx it will still execute if no errors.
- Methods which fetch data are the best candidates for this option.
NOT_SUPPORTED
- Indicates that the target method doesn’t require the transaction context to be propagated.
- Mostly those methods which run in a transaction but perform in-memory operations are the best candidates for this option.
NEVER
- Indicates that the target method will raise an exception if executed in a transactional process.
- This option is mostly not used in projects.
@Transactional (rollbackFor=Exception.class)
- Default is rollbackFor=RunTimeException.class
- In Spring, all API classes throw RuntimeException, which means if any method fails, the container will always rollback the ongoing transaction.
- The problem is only with checked exceptions. So this option can be used to declaratively rollback a transaction if Checked Exception occurs.
@Transactional (noRollbackFor=IllegalStateException.class)
- Indicates that a rollback should not be issued if the target method raises this exception.
Now the last but most important step in transaction management is the placement of @Transactional annotation. Most of the times, there is a confusion where should the annotation be placed: at Service layer or DAO layer?
@Transactional: Service or DAO Layer?
- The Service is the best place for putting @Transactional, service layer should hold the detail-level use case behavior for a user interaction that would logically go in a transaction.
- There are a lot of CRUD applications that don't have any significant business logic for them having a service layer that just passes data through between the controllers and data access objects is not useful. In these cases we can put transaction annotation on Dao.
- So in practice you can put them in either place, it's up to you.
- Also if you put @Transactional in DAO layer and if your DAO layer is getting resused by different services then it will be difficult to put it on DAO layer as different services may have different requirements.
- If your service layer is retrieving objects using Hibernate and let's say you have lazy initializations in your domain object definition then you need to have a transaction open in service layer else you will face LazyInitializationException thrown by the ORM.
- Consider another example where your Service layer may call two different DAO methods to perform DB operations. If your first DAO operation failed then other two may be still passed and you will end up inconsistent DB state. Annotating Service layer can save you from such situations.
Hope this article helped you.
https://dzone.com/articles/spring-transaction-management
No comments:
Post a Comment