Most J2EE architecture is built like this (or should be!):
- Actions (Struts)
- Services
- DAOs (Data access objects)
public List getAllActiveLegacyFeatures() throws Exception {
List features = fpsDao.grabAllActiveLegacyFeatures();
return features;
}
Moving on. So you really only have 2 choices. Wrap the transactions at the DAO layer or the Service layer. Lets begin by showing you how to "Wrap" a transaction. Here is some code that does it:
<bean id="ImportKeyDataServiceImplementation" class="cat.dds.fpsdma.services.ImportKeyDataService">
<constructor-arg index="0" ref="fpsDAO" />
</bean>
<bean id="ImportKeyDataService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="theTransactionManager" />
</property>
<property name="target">
<ref local="ImportKeyDataServiceImplementation" />
</property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
The first "bean" here is the actual object. Notice that on line 2 it has a DAO. Now this object should never be used, so we actually call it an "...Implementation". Notice that the second bean is named "ImportKeyDataService" It is not an implementation, but the object that we should use. (This is just how we did it on FPS. We just used this naming convention so we new that we should never use the "Implementation" objects). Notice that the Implementation object is referenced on line 9. This ties all this together. So, when you actually use the object "ImportKeyDataService" you will get a Wrapped transaction.
What does this give you? Lots. When any DAO call is made in the ImportKeyDataService object above, Hibernate will not commit anything. Batch updates and such automatically roll back correctly if there is an error thrown out of the ImportKeyDataService object. This would not happen if you wrapped the DAO. Every time you go in and back out of an object (the object looses scope) you commit. So, if you have a DAO doing something, it would commit every time you made a call.
Now there are two times when you want the DAO to be wrapped.
- If you are doing DB2 calls to CDID or some alien database, and you are just doing "selects", it is best to commit after every transaction. For some reason Mainframers like that.
- JUnits usually require commits to work properly. We make a junit for EVERY database call. They just don't work if you don't commit after each one. However, in this case, Spring makes this easy.