Tuesday, December 9, 2014

Spring Transactions

Any Banking Project with Transaction Management in Spring/Hibernate Useful for us...

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
Both activities are required to make sure that the transaction is complete. If you money is withdrawn and some problem occurs in the system then the transaction is cancelled and the money is credited back to your account and you can try it all over again.

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
In the case of local transactions the transaction is managed at the database level or the message provider level. Typically for JDBC this is achieved by setting theconnection.setAutoCommit(false) before the beginning of the database calls and calling connection.commit() at successfull completion of all activities or calling connection.rollback()if an exception is thrown. In Spring the connection can be obtained using DataSourceUtils.getConnection(dataSource) 
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!)



  • 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?
  • 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.
    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.
    PROPAGATION_MANDATORY
    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
    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.
    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
    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.

    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.
    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.
    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.
    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.
    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). 
  •         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);
    }  
  • 2 comments:

    1. Thanks for sharing this informative content , Great work
      Leanpitch provides online training in ICP CAT during this lockdown period everyone can use it wisely.
      ICP-CAT certification

      ReplyDelete

    Java 9 and Java11 and Java17, Java 21 Features

     Java 9 and Java11 and Java17 features along with explanation and examples in realtime scenarios Here's a detailed breakdown of Java 9, ...