Any Banking Project with Transaction Management in Spring/Hibernate Useful for us...
There are certain limitations to using the low level method. If the code within the setAutoCommit(false) and commit() delegates some activities to another method (say another DAO), then the only way to continue the transaction is to pass you instance of the connection to that Dao. This is not a good design strategy. Also, the low level method is prone to human errors (developers forgetting to commit or demarcate the transaction region). Also it does not work for transactions accross multiple databases or systems (e.g. database and message provider)
org.springframework.transaction.PlatformTransactionManager - This is the main class of the transaction API. It defines methods such as getTransaction(TransactionDefinition definition), commit(status) and rollback(status). The main implementors of these interface are JtaTransactionManager and DataSourceTransactionManager. To implement this interface it is advisable to extend the abstract class AbstractPlatformTransactionManager
org.springframework.transaction.support.AbstractPlatformTransactionManager - This abstract class implements the spring transaction workflow. It performs the following workflow operations - determine if there is existing transaction, apply propagation, suspend or resume transactions, perform rollback modifications.
org.springframework.jdbc.datasource.DataSourceTransactionManager - This is the concrete implementation of the PlatformTransactionManager via the AbstractPlatformTransactionManager for a JDBC datasource. It binds a JDBC datasource to the current thread. Note that the application code needs to retrieve the connection using DataSourceUtils.getConnection(DataSource) instead of DataSource.getConnection(). Spring's JdbcTemplate does this implicitly. However, if you have to use DataSource.getConnection() then wrap the datasource in TransactionAwareDataSourceProxy and pass that in the Dao to allow for spring managed trasactions. This transaction manager supports custom isolation levels and timeouts. Use this only for non-XA datasources.
org.springframework.transaction.jta.JtaTransactionManager - This is the JTA implementation of the PlatFormTransactionManager. It delegates the transaction management to a JTA provider. Use this transaction manager for distributed transactions
org.springframework.orm.hibernate4.HibernateTransactionManager- This is the concrete implementation of the PlatformTransactionManager for a single hibernate SessionFactory. It associates a hibernate session from the specified factory to a thread.
What are transaction attributes?
public interface PlatformTransactionManager {
What is a Transaction?
Transaction is an activity or group of activities that are performed as a single unit of work. The characteristic of a transaction is that either all the activities that are part of the transaction are performed or none are performed. In other words, even if one of the activity fails then all other activities are cancelled and the system comes back to the state it was in when the transaction was started. This can be best explained by an example. Lets say you are planning on a vacation to a beautiful island and you pick up a nice looking resort. You call them up and book a room. To confirm your booking, you need to transfer money to their account. Transferring money from your account to their account is considered a transaction and these are the two activities that happen in that transaction.
- Money is debited from your account
- Money is credited to the resorts account
Characteristics of a transaction (ACID)
The software industry coined the acronym ACID for characteristics that a transaction must have. ACID stands for Atomic, Consistent, Isolated and Durable- Atomic - Atomic says that either all activities of the transaction occur or none occur. i.e. even if one of the activity in the group fails that the other activities are cancelled (rolled back)
- Consistent - Once the transaction is complete the system is put back into a state that is properly defined. In our example, if the money were to be debited from your account and not credited to the resorts account then the system is not in consistent state since the money is now lost from the system. From a database point of view, consistent also means that all times none of the database constraints are violated. So even if you do not commit a transaction, at no point should a foreign key constraint or unique key constraint be violated
- Isolated - The transaction allows multiple people to work on the same data in a way that one transaction does not affect the data of the rest of the system. Therefore, two transactions can occur simultaneously without dirty reads. This is generally accomplished by locking the rows of the database or the database table
- Durable - The changes of the transaction are persisted to a permanent storage.
Transaction Strategies
Transaction strategies define how you want to implement transactions in your applications. There are mainly three ways to implement a transaction:
- Local Transactions
- Programmatic Implementation using Spring Transaction Managers and Transaction Templates
- Declarative Implementation in the Spring Application XML or using Annotations
There are certain limitations to using the low level method. If the code within the setAutoCommit(false) and commit() delegates some activities to another method (say another DAO), then the only way to continue the transaction is to pass you instance of the connection to that Dao. This is not a good design strategy. Also, the low level method is prone to human errors (developers forgetting to commit or demarcate the transaction region). Also it does not work for transactions accross multiple databases or systems (e.g. database and message provider)
In Programmatic transaction the user does not have to work at the connection level. The actual work of managing connections is delegated to the transaction provider and the user only has to manage the transactions. Declarative transactions use the power of spring in defining the transactions in the xml file or through annotations. We discuss programmatic transactions in this tutorial and declarative transactions in this tutorial.
Important Classes in the Spring Transaction API.
It would be good to know the basic classes of the spring transaction API before we go into the actual implementation. We cover some basic classes here, look at the java docs for more details. (or the source code!)
Spring transactions allow setting up the propagation behavior, isolation, timeout and read only settings of a transaction. Before we delve into the details, here are some points that need to be kept in mind
- Isolation level and timeout settings get applied only after the transaction starts.
- Not all transaction managers specify all values and may throw exception with some non default values
Propagation
PROPAGATION_REQUIRED
This attribute tells that the code needs to be run in a transactional context. If a transaction already exists then the code will use it otherwise a new transaction is created. This is the default and mostly widely used transaction setting.
This attribute tells that the code needs to be run in a transactional context. If a transaction already exists then the code will use it otherwise a new transaction is created. This is the default and mostly widely used transaction setting.
PROPAGATION_SUPPORTS
If a transaction exists then the code will use it, but the code does not require a new one. As an example, consider a ticket reservation system. A query to get total seats available can be executed non-transactionally. However, if used within a transaction context it will deduct tickets already selected and reduce them from the total count, and hence may give a better picture. This attribute should be used with care especially when PROPAGATION_REQUIRED or PROPAGATION_REQUIRES_NEW is used within a PROPAGATION_SUPPORTS context.
If a transaction exists then the code will use it, but the code does not require a new one. As an example, consider a ticket reservation system. A query to get total seats available can be executed non-transactionally. However, if used within a transaction context it will deduct tickets already selected and reduce them from the total count, and hence may give a better picture. This attribute should be used with care especially when PROPAGATION_REQUIRED or PROPAGATION_REQUIRES_NEW is used within a PROPAGATION_SUPPORTS context.
PROPAGATION_MANDATORY
Participates in an existing transaction, however if no transaction context is present then it throws a TransactionRequiredException
Participates in an existing transaction, however if no transaction context is present then it throws a TransactionRequiredException
PROPAGATION_REQUIRES_NEW
Creates a new transaction and if an existing transaction is present then it is suspended. In other words a new transaction is always started. When the new transaction is complete then the original transaction resumes. This transaction type is useful when a sub activity needs to be completed irrespective of the containing transaction. The best example of this is logging. Even if a transaction roll backs you still want to preserve the log statements. Transaction suspension may not work out of the box with all transaction managers, so make sure that the transaction manager supports transaction suspension
Creates a new transaction and if an existing transaction is present then it is suspended. In other words a new transaction is always started. When the new transaction is complete then the original transaction resumes. This transaction type is useful when a sub activity needs to be completed irrespective of the containing transaction. The best example of this is logging. Even if a transaction roll backs you still want to preserve the log statements. Transaction suspension may not work out of the box with all transaction managers, so make sure that the transaction manager supports transaction suspension
PROPAGATION_NOT_SUPPORTED
This attribute says that transaction is not supported. In other words the activity needs to be performed non-transactionally. If an existing transaction is present then it is suspended till the activity finishes.
This attribute says that transaction is not supported. In other words the activity needs to be performed non-transactionally. If an existing transaction is present then it is suspended till the activity finishes.
PROPAGATION_NEVER
This attributes says that the code cannot be invoked within a transaction. However, unlike PROPAGATION_NOT_SUPPORTED, if an existing transaction is present then an exception will be thrown
This attributes says that the code cannot be invoked within a transaction. However, unlike PROPAGATION_NOT_SUPPORTED, if an existing transaction is present then an exception will be thrown
PROPAGATION_NESTED
The code is executed within a nested transaction if existing transaction is present, if no transaction is present then a new transaction is created. Nested transaction is supported out of the box on only certain transaction managers.
The code is executed within a nested transaction if existing transaction is present, if no transaction is present then a new transaction is created. Nested transaction is supported out of the box on only certain transaction managers.
Isolation
Isolation is a property of a transaction that determines what effect a transaction has on other concurrent transactions. To completely isolate the transaction the database may apply locks to rows or tables. Before we go through the transaction levels, let us look at some problems that occur when transaction 1 reads data that is being modified by transaction 2.
- Dirty Reads- Dirty reads occur when transaction 2 reads data that has been modified by transaction 1 but not committed. The problem occurs when transaction 1 rollbacks the transaction, in which case the data read by transaction 2 will be invalid.
- Non Repeatable Reads- Nonrepeatable reads happen when a transaction fires the same query multiple times but receives different data each time for the same query. This may happen when another transaction has modified the rows while this query is in progress.
- Phantom Reads - Phantom reads occur when the collection of rows returned is different when a same query is executed multiple times in a transaction. Phantom reads occur when transaction 2 adds rows to a table between the multiple queries of transaction 1.
The following isolation levels are supported by spring
ISOLATION_DEFAULT
Use the isolation level of the underlying database.
Use the isolation level of the underlying database.
ISOLATION_READ_UNCOMMITTED
This is the lowest level of isolation and says that a transaction is allowed to read rows that have been added but not committed by another transaction. This level allows dirty reads, phantom reads and non repeatable reads.
This is the lowest level of isolation and says that a transaction is allowed to read rows that have been added but not committed by another transaction. This level allows dirty reads, phantom reads and non repeatable reads.
ISOLATION_READ_COMMITTED
This level allows multiple transactions on the same data but does not allow uncommited transaction of one transaction to be read by another. This level, therefore, prevents dirty reads but allows phantom reads and nonrepeatable reads. This is the default isolation setting for most database and is supported by most databases.
This level allows multiple transactions on the same data but does not allow uncommited transaction of one transaction to be read by another. This level, therefore, prevents dirty reads but allows phantom reads and nonrepeatable reads. This is the default isolation setting for most database and is supported by most databases.
ISOLATION_REPEATABLE_READ
This level ensures that the data set read during a transaction remains constant even if another transaction modifies and commits changes to the data. Therefore if transaction 1 reads 4 rows of data and transaction 2 modifies and commits the fourth row and then transaction 1 reads the four rows again then it does not see the modifications made by transaction 2. (It does not see the changes made in the fourth row by the second transaction). This level prevents dirty reads and non repeatable reads but allows phantom reads.
This level ensures that the data set read during a transaction remains constant even if another transaction modifies and commits changes to the data. Therefore if transaction 1 reads 4 rows of data and transaction 2 modifies and commits the fourth row and then transaction 1 reads the four rows again then it does not see the modifications made by transaction 2. (It does not see the changes made in the fourth row by the second transaction). This level prevents dirty reads and non repeatable reads but allows phantom reads.
ISOLATION_SERIALIZABLE
This is the highest isolation level. It prevents dirty reads, non repeatable reads and phantom reads. This level prevents the situation when transaction 1 performs a query with a certain where clause and retrieves say four rows, transaction 2 inserts a row that forms part of the same where clause and then transaction 1 reruns the query with the same where clause but still sees only four rows (does not see the row added by the second transaction).
This is the highest isolation level. It prevents dirty reads, non repeatable reads and phantom reads. This level prevents the situation when transaction 1 performs a query with a certain where clause and retrieves say four rows, transaction 2 inserts a row that forms part of the same where clause and then transaction 1 reruns the query with the same where clause but still sees only four rows (does not see the row added by the second transaction).
Sequence
of action that will be performed to complete database operation and
its management is known as Transaction Management. All these action
in combination will be treated as ONE action only. So that DB doesn’t
fall in inconsistent mode ever. For more details you can search for
ACID property of relation DB.
Type
of Transaction Management In
J2EE, Transaction Management can be divided in two types.
Global
Transaction
Local
Transaction
Global
Transaction
Use
to work with multiple transaction resources like RDBMS or Message
Queue (Pros)
Managed
by Application Server (WebSphere, Weblogic) using JTA (Cons)
JNDI
is required to use JTA
Code
can not be reused as JTA is available at server level(Cons)
Example
of Global Transaction : EJB CMT
Local
Transaction
Use
to work with specific resource(transaction associated with JDBC)
Can
not work across multiple transaction resource opposite to Global
transaction (cons)
Most
of web application uses only single resources hence it is best option
to use in normal app.
Spring
Framework Transaction Management
As
you can see above there are some pros and cons associated with both
approach. Spring transaction management tries to resolve the problem
of both transactions. Consistent programming model approach can be
used in any environment. Same code will work for different
transactions management in different environment.
Different
Approach for transaction management
Spring
supports two different approach for transaction management.
Programmatic
Transaction Management
Here
you will write code for transaction management.Spring API dependency.
Not good for maintenance. Good for development. Flexibity.
Declarative
Transaction Management
Here
you will use XML or annotation for transaction management. Less
flexible but preferable over programmatic approach. In normal case no
code is required for transaction management.
Spring
transaction management abstraction
To
understand transaction mangement you should understand
abstraction(Transaction strategy) in Spring. Which is defined in
Spring using PlatformTransactionManager Interface.
public interface PlatformTransactionManager {
TransactionStatus
getTransaction(TransactionDefinition definition)
throws
TransactionException;
void
commit(TransactionStatus status) throws TransactionException;
void
rollback(TransactionStatus status) throws TransactionException;
}
As
you can see in PlatformTransactionManager Interface all methods throw
TransactionException. This Exception itself is UncheckedException
means developer is not forced to handle these exceptions.
TransactionDefinition
TransactionDefinition
is an Interface which specifies below 4 points.
Isolation
Propagation
Timeout
Read-Only
status
Isolation
: Degree
to which particular transaction is isolated from other Transaction.
Below is the list of Isolation level and their details
DEFAULT
:
Default isolation level. It uses the isolation of underlying data
Source.
READ_COMMITTED
:
Dirty reads NOT supported; Non-repeatable reads and Phantom reads can
occur.
READ_UNCOMMITTED
:
Dirty reads / Non-repeatable reads / Phantom reads all can occur.
REPEATABLE_READ
: Dirty
reads and non-repeatable reads are prevented; phantom reads can
occur.
SERIALIZABLE:
Dirty reads, non-repeatable reads and phantom reads are prevented.
Propagation
MANDATORY
:
Support a current transaction
NESTED:
Execute
within a nested transaction if a current transaction exists
NEVER:
Execute
non-transaction ally
NOT_SUPPORTED
: Execute
non-transaction ally
REQUIRED
: Support
a current transaction
REQUIRES_NEW
: Create
a new transaction, suspend the current transaction if one exists.
SUPPORTS
: Support
a current transaction, execute non-transaction if none exists.
Timeout
:
This
setting is used to define how long this transaction may run before
timing out (candidate for rolled back by the underlying transaction
infrastructure).
Read-Only
Status:
This
setting is used to specify the a read-only transaction. As read only
transactions does not modify any data. Hence it is optimized in some
case.
Dependency
Injection (DI) : In Spring
Dependency
Injection is at the heart of the Spring framework. The basic concept
of the Dependency Injection is that framework provides the
dependencies of class itself.
We
need not create the objects instead we just define how they should be
created and IoC container will create the objects for us.
For
example if we have two classes ‘ClassA’ and ‘ClassB’. ClassA
is dependent on ClassB then container will inject the instance of
ClassB in an instance of ClassA.
This
feature is very useful specially in a large and complex applications
where it is very important to have the classes loosely coupled. In
other words, Dependency Injection allows us to remove the hard-coded
dependencies and make our application loosely coupled, extendable and
maintainable
Aspect
Oriented Programming (AOP):
Logic
of any application consists of two parts-
Business
Logic – is the actual logic that is intended to achieve the
functionality.
Cross
Cutting Concerns – is the utility code that can be applied to
business logic and required at several parts of the application like
logging, transaction management etc.
The
basic principle of AOP is finding common tasks which is required at
many places in the code and does not belong to the business logic
.Aspect Oriented Programming (AOP) provides a way of modularizing
application logic, so that each module addresses a distinct concern.
For
example if we want to write a log statement on entry of every method
of our application then instead of having logging logic at several
places in an application, AOP provides a means of modularizing this
logic, and applying it to various parts of the application at run
time. This provides a clear Separation of Concerns and need not to be
tied with business logic.
Spring
Framework transaction management vs
Hibernate Transaction Management:
Spring transaction just allows to define declarative
transaction management rules at convenient way via adding additional
abstraction layer above the underlying transaction infrastructure.
The later may be either single-resource bound transaction (jms
transaction, jdbc transaction, hibernate transaction) or
multiple-resource one (jta transaction). Spring tx layer just
understands when to delegate start/commit/rollback transaction task
to the underlying tx layer.
E.g. if you use annotation-based transaction definition approach, you
can assume that spring creates new hibernate transaction when you
call the method marked by @Transaction and commits/rollbacks it
according to the processing flow. I.e. its only task is to perform
necessary calls at the underlying tx level.
The
real advantages are:
Lightweight
declarative syntax. Compare:
public
void saveEmployee(Employee e) {
Session s = sf.getCurrentSession();
s.getTransaction().begin();
s.save(e);
s.getTransaction().commit();
}
and
@Transactional
public
void saveEmployee(Employee e) {
sf.getCurrentSession().save(e);
}
Flexible
transaction propagation. Imagine that now you need to execute this
saveEmployee() method as a part of a complex transaction. With manual
transaction management, you need to change the method since
transaction management is hard-coded. With Spring, transaction
propagation works smoothly:
@Transactional
public
void hireEmployee(Employee e) {
dao.saveEmployee(e);
doOtherStuffInTheSameTransaction(e);
}
Automatic
rollback in the case of exceptions.
TL;DR
:Hibernate
deals with database specific transactions, whereas spring provides a
general transaction management service.
@Transactional
is
a nice way of configuring transaction management behavior
Transactions
:
Transactions
are basically units of work (ie changes to something) that are
managed as a single operation that can be either committed or rolled
back. There are lots of different types of transactions in the java
world - database, messaging systems like JMS, inter application
transactions (for those who are not faint of heart) or anything else
that may need to be included in a transaction. In the Java standard
transactions are managed using the Java Transaction API which sets
the rules for how to participate in a transaction.
Hibernate
:
Hibernate
is an ORM for abstracting database components to Java objects, so its
transactions are specifically related to changes made within a
database. A transaction may be made up of one or many writes to
various database tables that are all committed once the operation is
completed. Rolling back the transaction, eg f there are any errors
during the operation, allows all the changes to be undone.
Spring
:
At
its lowest level Spring is a application framework for managing
configuration and dependencies between objects. In addition it also
provides an interface for managing higher level services that are
used in modern applications such as databases, messaging services,
MVC frameworks and transactions.
Spring
is designed to be used as an all-encompassing master of objects and
services within your application, so its concept of a transaction is
at a higher level than the database specific transactions that
hibernate concerns itself with. Spring Transactions are designed to
give you fine grained control of all your transactional resources
while abstracting away the often messy coding required to co-ordinate
the transactions.
@Transactional
Spring
provides a few different methods for using transactions - among
others there xml based aspects, coding to the API and annotation
based declarative transactions. The annotation based transactions are
handy because you don’t need to add the transaction management
boilerplate code to your app (even using PlatformTransactionManager
via the API has quite a bit of coding overhead).
So
basically what happens with @Transactional is that at runtime spring
scans your code base for @Transactional classes and methods and wraps
them up in the transaction specific management code, based on what
you have configured via the annotation. So a method like this:
@Transactional(propagation
= REQUIRES_NEW, rollbackFor = {Exception.class})
public
void saveAndSendMessage(Foo foo) throws Exception {
dbManager.save(foo);
Bar
bar = transform(foo);
jmsSystem.send(bar);
}
Nice Post
ReplyDeletekajal hot
Thanks for sharing this informative content , Great work
ReplyDeleteLeanpitch provides online training in ICP CAT during this lockdown period everyone can use it wisely.
ICP-CAT certification