Using PlatformTransactionManager

PlatformTransactionManager is at the center of discussing Spring's transaction management API. It has the functionalities to commit and rollback. It also provides a method that returns the currently active transaction. As it's an interface, it can be easily mocked or stubbed whenever required. Spring provides DataSourceTransactionManager, HibernateTransactionManager, CciLocalTransactionManager, and JtaTransactionManager, as a few of the implementations of PlatformTransactionManager. To use PlatformTransactionManager, any implementation of it can be injected in the bean to use for transaction management. Further, the objects of TransactionDefinition and TransactionStatus can be used to rollback or commit the transaction.

Before going ahead, we need to discuss a very important point. Generally, the application requirement decides whether to apply transaction to the service layer or to DAO. However, it is still a debatable question whether to apply transaction to the DAO layer or to the service layer. Applying the transaction to the DAO layer keeps the transaction shorter, but the biggest problem will occur for multiple transactions. Moreover, the concurrency has to be made with very much care and unnecessarily the complexity will be increased. The transaction, when applied to the service layer, facilitates the DAOs to use a single transaction instead of multiple transactions. We will apply the transaction to the service layer in our application.

To apply transaction management in an application, we can think about the following points:

  • Whether to apply the transaction to the DAO layer or the Service layer
  • Decide whether to use declarative transaction or programmatic transaction management
  • Define PlatformtransactionManager to use in beans configuration
  • Decide the transaction attributes such as propagation behavior, isolation level, read only, timeout, and more, to be defined for the transaction
  • According to programmatic or declarative transaction management, add the attributes to the transaction either in code or in the configuration of the XML file

Let's use a transaction for better understanding. We will use JDBC operations in the Ch03_JdbcTemplate application that was developed in Chapter 3, Accelerate with Spring DAO, as our base application. Let's follow these steps to use transactions using PlatformTransactionManager:

  1. Create a new Java application named Ch05_PlatformTransactionManager and add all required JAR files for Spring core: Spring-jdbc, Spring-transaction, Spring-aop, commons-logging, and mysql-connector.
  2. Copy or create Book.java in the com.packt.ch03.beans package.
  1. Copy or create BookDAO.java and BookDAO_JdbcTemplate.java in the com.packt.ch03.dao package. The final outline of the application is as follows:
  1. We will add a new method in BookDAO to search the book because, before adding, it will be important to find out if there is any book in the Book table with the same ISBN. If it already exists, we don't want to unnecessarily go ahead to add it again. The newly added method is as follows:
public Book searchBook(longISBN); 
  1. The BookDAO_JdbcTemplate needs to override the newly added method in the interface, as follows:
@Override 
public Book serachBook(longISBN) { 
  // TODO Auto-generated method stub 
  String SEARCH_BOOK = "select * from book where ISBN=?"; 
  Book book_serached = null; 
  try { 
    book_serached = 
jdbcTemplate.queryForObject(SEARCH_BOOK, new Object[] { ISBN }, new RowMapper<Book>(){ @Override public Book mapRow(ResultSet set, int rowNum) throws SQLException { Book book = new Book(); book.setBookName(set.getString("bookName")); book.setAuthor(set.getString("author")); book.setDescription(set.getString("description")); book.setISBN(set.getLong("ISBN")); book.setPrice(set.getInt("price")); book.setPublication(set.getString("publication")); return book; } }); return book_serached; } catch (EmptyResultDataAccessException ex) { return new Book(); } }

We have added an anonymous inner class, which is implementing RowMapper. RowMapper is used to bind column values that are fetched from the database table to the object of Book returned by the queryForObject() method. The code is searching for the book, and then the column values from ResultSet are bounded to the Book object. We returned an object with default values just for our business logic.

  1. Add the BookService interface as a service layer in the com.packt.ch05.service package with the following method signatures:
public interface BookService { 
  public Book searchBook(long ISBN); 
  public boolean addBook(Book book); 
  public boolean updateBook(long ISBN, int price); 
  public boolean deleteBook(long ISBN); 
} 
  1. Create BookServiceImpl implementing BookService. As it's for service, annotate the class with @Service.
  1. Add two data members to the class: first, of type PlatformTransactionManager, to handle transactions, and second, of type BookDAO, to perform JDBC operations. For dependency injection, annotate both of them by @Autowired.
  2. Firstly, let's develop the searchBook() method of the service layer to handle read-only transaction in two steps, which are as follows:
    1. Create an instance of TransactionDefinition.
    2. Create an instance of TransactionStatus that will be obtained from TransactionManager using an instance of TransactionDefinition created in the previous step. TransactionStatus will provide the status information of transaction, which will be used to commit or rollback the transaction. Don't worry, in a while, we will write the code that will clear everything.
    3. Here, make the transaction read-only by setting the property to true, as we just want to search the book and don't want to perform any updating on the database side. The code developed up until this step is as follows:
@Service(value = "bookService") 
public class BookServiceImplimplements BookService { 
      @Autowired 
      PlatformTransactionManager transactionManager; 
 
      @Autowired 
      BookDAO bookDAO; 
 
      @Override 
      public Book searchBook(longISBN) { 
         TransactionDefinition definition = new 
DefaultTransactionDefinition(); TransactionStatus transactionStatus = transactionManager.getTransaction(definition); //set transaction as read-only ((DefaultTransactionDefinition) definition).setReadOnly(true); Book book = bookDAO.serachBook(ISBN); return book; } // other methods from BookService }

We can set other properties, such as isolation level, propagation, and timeout, the same way we updated the read-only property of the transaction.

  1. Let's add the addBook() method to the service layer to find out whether the book with the same ISBN already exists and, if not, insert a row in table. The code is as follows:
@Override 
public boolean addBook(Book book) { 
  // TODO Auto-generated method stub 
  TransactionDefinition definition = new 
  DefaultTransactionDefinition(); 
  TransactionStatustransactionStatus =  
    transactionManager.getTransaction(definition); 
 
  if (searchBook(book.getISBN()).getISBN() == 98564567l) { 
    System.out.println("no book"); 
    int rows = bookDAO.addBook(book); 
    if (rows> 0) { 
      transactionManager.commit(transactionStatus);  
      return true; 
    } 
  } 
  return false; 
} 

In the code, the transactionManager.commit() method will commit the data permanently to the book table.

  1. In the same way, let's add the deleteBook and updateBook() methods, as shown in the following piece of code:
@Override 
public boolean updateBook(longISBN, intprice) { 
  TransactionDefinition definition = new 
    DefaultTransactionDefinition(); 
  TransactionStatus transactionStatus = 
    transactionManager.getTransaction(definition); 
  if (searchBook(ISBN).getISBN() == ISBN) { 
    int rows = bookDAO.updateBook(ISBN, price); 
    if (rows> 0) { 
      transactionManager.commit(transactionStatus); 
      return true; 
    } 
  } 
  return false; 
} 
 
@Override 
public boolean deleteBook(longISBN)  
{ 
  TransactionDefinition definition = new 
    DefaultTransactionDefinition(); 
  TransactionStatus transactionStatus =  
    transactionManager.getTransaction(definition); 
  if (searchBook(ISBN).getISBN() != 98564567l) { 
    boolean deleted = bookDAO.deleteBook(ISBN); 
    if (deleted) { 
      transactionManager.commit(transactionStatus); 
      return true; 
    } 
  } 
  return false; 
} 
  1. Copy or create connection_new.xml for the bean configurations. Add a bean for DataSourceTransactionManager, as we saw earlier while discussing how to configure PlatformTransactionManager using DataSource.
  2. Update package scanning from XML, as we want to consider the newly added package as well. The updated configuration is as follows:
<context:component-scan base- package= 
  "com.packt.*"></context:component-scan> 
  1. The final set will be to add main code in MainBookService_operation.java, which will invoke methods from the service layer using the BookServiceImpl object, as we did earlier for the BookDAO_JdbcTemplate object. The code is as follows:
public static void main(String[] args) { 
  // TODO Auto-generated method stub 
  ApplicationContext context = new 
    ClassPathXmlApplicationContext("connection_new.xml"); 
  BookService service = (BookService)  
    context.getBean("bookService"); 
  // add book 
  boolean added = service.addBook(new Book("Java EE 7  
     Developer Handbook", 97815674L, "PacktPub 
     publication", 332,"explore the Java EE7 
     programming", "Peter pilgrim")); 
  if (added) { 
     System.out.println("book inserted successfully"); 
  } else 
  System.out.println("SORRY!cannot add book"); 
  // update the book 
  boolean updated = service.updateBook(97815674L, 800); 
  if (updated) { 
    System.out.println("book updated successfully"); 
  } else 
  System.out.println("SORRY!cannot update book"); 
  // delete the book 
  boolean deleted = service.deleteBook(97815674L); 
  if (deleted) { 
    System.out.println("book deleted successfully"); 
  } else 
  System.out.println("SORRY!cannot delete book"); 
} 
  1. On execution, we will get the message denoting that the book is inserted, updated, and deleted successfully.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.12.172