Skip to main content

Enterprise Application's Logical Layers and where to manage Transactions

Recently I came across an application which manage transaction's at Dao layer that means there is no proper transaction management and if an exception occurs during runtime will leave inappropriate data in database.


Consider this simple Architectural layers





Brief description of each block starting from the bottom.

DB1 .. DBn → Databases, an application sometimes refers to multiple databases and simple application has one.

Dao Layer →  Encapsulates logic to add, update, delete and read data from Databases using JPA, Hibernate or JDBC.

Entity/Dto → Simple Pojo classes which encapsulate database entities

WebServices Client → Another Integration Layers like Dao which communicates with other systems via SOAP, JMS etc.

Service Layer → This layer contains business logic which encapsulate the data (Dao & Webservices client) they operate on and provide hardened interfaces as the only way to access their functionality. This approach reduces side effects and allows services to evolve at their own pace without impacting the other components of the overall system.

UI/Controller → If you use any MVC framework then this layer contains Controller or Action classes which directly serve browser requests and delegates all operations to Service Layers Classes i.e. they don't have any business logic in them.

Web Services → This layer contains Web Services or External facing API's if you plan to expose some functionality for other systems to integrate via SOAP, REST, RMI etc. Also this should just delegate all functionality to Service Layers classes, Main reason we have this extra layer to expose some functionality is to have its own space to evolve with different revisions without impacting the overall system, this separation is very important if you system needs to involve over time and external changes.



Coming back to the original topic as which layer to manage transactions, also you can clearly see in the Architecture diagram above that Service Layer lies at the heart of the system exposing business logic to UI and other API's and hence that's where Transactions should be manage.


Checkout this sample transaction management code

/**
*
* @author intesar
*/
@Service
public class UserServiceImpl implements UserService {

   /**
    * Dummy Use Case # 33
    * Admin can select multiple users on UI page and update the active status and then saves
    * updates multiple users in a single transactions
    * @param users
    */
   @Override
   @Transactional(propagation = Propagation.REQUIRED)
   public void updateUsers(List<User> users){
       for ( User user: users ) {
           userDao.merge(user);
       }
   }
   
   
   @Autowired
   protected UserDao userDao;
   
   protected static final Log log = LogFactory.getLog(UserServiceImpl.class);
}

As you can see in the above code snippet updateUsers(..) method part of Service Layer class,  updates multiple users in a single operation and if any user update fails then entire operation rollsback. However this not possible if we are managing transactions at Dao layer.

I am using Spring framework to manage my transactions though you can use JEE or any other framework.

Comments

javin paul said…
I didn't get the point completely , to me most of the transaction completes when data successfully entered into database, so either you could have synchronous database insertion or asynchronous database insertion , in case of asynchronous database insertion there is chance of data loss if data stays in temp memory and application dies. What's your opinion ?

Javin
Why String is immutable in Java
Don Stevo said…
I think the point stated here is:

If your service method calls several DAO methods, when you put your transaction management in the DAO layer each previous DAO method will be comitted, even if a subsequent DAO method throws an exception. Possibly erronous data will remain in the database this way.

If your transaction management is around your Service method, when one of the DAO methods throws an Exception your entire Service call will be rollbacked and no modified data will remain in the database.
This comment has been removed by the author.
You are forgetting a BusinessObject layer between the Services layer and the DAO layer. All the business logic must be inside this layer, and its methods can be transactional.
The adventage of having a BO layer is that other technologies than WS (eg JMS) can access to the BO logic, and you can make transactional multiple DAO calls.
In brief, having a BO layer have to adventages:
1) solves your problem of transactinality
2) makes your app more extensible (for other communication technologies)

Best regards

Popular posts from this blog

Access multiple Databases in JPA

According to JPA specification we can define multiple "persistence-unit" elements (i.e. like below) in persistence.xml file and can easily refer them inside Dao layers as this. public class PolarDaoImpl {     @PersistenceContext(unitName="PolarPU")     protected EntityManager entityManager; -- } public class BearDaoImpl {     @PersistenceContext(unitName="BearPU")     protected EntityManager entityManager; -- } Checkout sample persistence.xml <?xml version="1.0" encoding="UTF-8"?> <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">     <!-- Database 1 -->     <persistence-unit name="PolarPU" transaction-type="RESOURCE_LOCAL">         <

JPA 2 new feature @ElementCollection explained

@ElementCollection is new annotation introduced in JPA 2.0, This will help us get rid of One-Many and Many-One shitty syntax. Example 1: Stores list of Strings in an Entity @Entity public class Users implements Serializable {     private static final long serialVersionUID = 1L;     @Id     @GeneratedValue(strategy = GenerationType.AUTO)     private Long id;     @ElementCollection     private List<String> certifications = new ArrayList <String> ();     public Long getId() {         return id;     }     public void setId(Long id) {         this.id = id;     }     public List <String> getCertifications() {         return certifications;     }     public void setCertifications(List <String> certifications) {         this.certifications = certifications;     } .. }         Users u = new Users();         u.getCertifications().add("Sun Certified Java Programmer");         em.persist(u); Generated Tables    Users    Co

Reuse JPA Entities as DTO

Note : Major design advantages of JPA Entities are they can detached and used across tiers and networks and later can by merged. Checkout this new way of querying entities in JPA 2.0 String ql = " SELECT new prepclass2.Employee (e.firstname, e.lastname) FROM Employee e "; List<Employee> dtos = em.createQuery(ql).getResultList(); The above query loads all Employee entities but with subset of data i.e. firstname, lastname. Employee entity looks like this. @Entity @Table(name="emp") public class Employee implements Serializable {     private static final long serialVersionUID = 1L;     @Id     @GeneratedValue(strategy = GenerationType.AUTO)     private Long id;     @Column     private String firstname;     @Column     private String lastname;     @Column     private String username;     @Column     private String street;     @Column     private String city;     @Column     private String state;     @Column     private String zipc