I would like to discuss an issue I find it could be relevant to the way applications are designed, in terms of layers.
It's already assumed that the best and simplest layer architecture for a web application (and in general) should be made of three layers: MVC, business and data access layer. Also nearly everyone agrees that the transactional issues should affect to the business layer, and not the data access layer (due, for example, to the fact that many times several data access objects, or even business objects, are involved within a transaction).
From this point of view, if we use Spring's declarative transaction manager to inject transactionality in our application using Hibernate, we have to do something similar to:
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor .TransactionProxyFactoryBean">
<property name="transactionManager">
<ref local="transactionManager" />
</property>
<property name="target">
<ref local="myBOTarget"></ref>
</property>
<property name="transactionAttributeSource">
<value>
com.deltar.common.bo.BO.load*=PROPAGATION_REQUIRED ,readOnly
com.deltar.common.bo.BO.save*=PROPAGATION_REQUIRED
com.deltar.common.bo.BO.delete*=PROPAGATION_REQUIR ED
</value>
</property>
</bean>
As you can see, this fragment of code indicates that whenever a method called "load*" in MyBOTarget class may be executed by the application, transactionality must be applied through a Dynamic Proxy.
This works great, you must know for sure, but I have come with an inconvenience I will like to discuss next.
The inconvenience is about exception handling. As declarative transactionality should be applied to business objects (BO) in the business layer, the following phases are executed:
1) A method call is invoked on MyBOTarget
2) The proxy receives the method call and then (we suppose it is a transactional method):
2.1) Starts a transaction (we suposse no transaction was active yet)
2.2) Delegates the method call to MyBOTarget
2.3) Ends the transaction (usually the transaction manager does a commit)
3) The method call ends
If you take a look at this step-by-step list, if an exception is thrown on step 2.3), which occurs out of the scope of the business object, i.e. the exception cannot be captured by the MyBOTarget object, then the exception will be propagated to the upper layer, i.e. the MVC layer.
So let's suppose that the commit operation throws an exception due to required fields that were NULL. If so, then we will end up with a DataAccessException leaving the data access layer, bypassing the business layer (as we cannot capture it due to the proxy), and finally getting to the MVC layer. In my opinion, this situation breaks completely with the architecture and is not desirable at all.
And here comes my question:
How can we solve this inconvenience? Should we add one more layer between the business layer and the data access layer, so the transactionality be applied in this new layer, and let the old business layer handle this "special" exceptions in something similar as a façade?
Looking forward to hearing your feedback about this issue.
==========
Enrique Medina


Reply With Quote