最近看了看社群的精華貼,知道原來service之間是可以嵌套事務的,前些日子還托同僚去網絡查,險些聽信了網上事務隻能封裝對DAO一層的操作的說法。 于是開始動手試驗,照新的觀點,隻要兩個事務傳播屬性都為PROPAGATION_REQUIRED即可。
相關檔案如下:(JavaEYE的編輯器總是出錯,原來是不支援IE6)
ServiceA 定義:
package ht.business.test;
import ht.business.dao.BusinessDAO;
import ht.business.model.Business;
public class BusinessService {
private BusinessDAO businessDAO=null;
/**
* @return businessDAO
*/
public BusinessDAO getBusinessDAO() {
return businessDAO;
}
/**
* @param businessDAO 要設定的 businessDAO
*/
public void setBusinessDAO(BusinessDAO businessDAO) {
this.businessDAO = businessDAO;
}
public Business addBusiness(){
Business b=new Business();
b.setMaker("12345678901234");//15位合法長度
businessDAO.save(b);
return b;
}
}
Service B 定義:
package ht.workflow.test;
import ht.workflow.dao.WorkTabDAO;
import ht.workflow.model.WorkTab;
import ht.business.model.Business;
import ht.business.test.*;
public class WorkflowService {
private WorkTabDAO workTabDAO=null;
private BusinessService businessService=null;
/**
* @return businessService
*/
public BusinessService getBusinessService() {
return businessService;
}
/**
* @param businessService 要設定的 businessService
*/
public void setBusinessService(BusinessService businessService) {
this.businessService = businessService;
}
/**
* @return workTabDAO
*/
public WorkTabDAO getWorkTabDAO() {
return workTabDAO;
}
/**
* @param workTabDAO 要設定的 workTabDAO
*/
public void setWorkTabDAO(WorkTabDAO workTabDAO) {
this.workTabDAO = workTabDAO;
}
public void addWorkTab(){
//調用service A的方法
Business b=businessService.addBusiness();
WorkTab wt=new WorkTab();
wt.setWorktabid(ht.util.UuidGenerator.createId());
wt.setWorkdataid(b.getBusinessid());
wt.setWorkflowtype("0001");
//error when wt.setStats("1111111");
wt.setStatus("1");
workTabDAO.save(wt);
}
}
測試類定義:
package ht;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.dao.DataAccessException;
import ht.workflow.test.*;
public class TestWB {
private static ApplicationContext ctx;
/**
* @param args
*/
public static void main(String[] args) {
// TODO 自動生成方法存根
String[] paths = {"D:/eclipse/workspace/htoa/htioas/WEB-INF/transContext.xml"};
ctx = new FileSystemXmlApplicationContext(paths);
WorkflowService wfs=(WorkflowService)ctx.getBean("workflowManager");
try{
wfs.addWorkTab();
}catch(DataAccessException e){
e.printStackTrace();
}
}
}
applicationcontext.xml定義:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName"
value="oracle.jdbc.driver.OracleDriver">
</property>
<property name="url"
value="jdbc:oracle:thin:@192.168.1.7:1521:htioas">
</property>
<property name="username" value="htec"></property>
<property name="password" value="htecioas"></property>
</bean>
<bean id="nativeJdbcExtractor"
class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor"
lazy-init="true" />
<bean id="lobHandler"
class="org.springframework.jdbc.support.lob.OracleLobHandler"
lazy-init="true">
<property name="nativeJdbcExtractor">
<ref bean="nativeJdbcExtractor" />
</property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="lobHandler">
<ref bean="lobHandler" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.OracleDialect
</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.jdbc.batch_size">50</prop>
<prop key="hibernate.jdbc.use_streams_for_binary">
true
</prop>
</props>
</property>
<property name="mappingResources">
<list>
<!-- BUSINESS workflow begin -->
<value>ht/business/model/Business.hbm.xml</value>
<value>ht/workflow/model/WorkTab.hbm.xml</value>
</list>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="workflowProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" lazy-init="true">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<bean id="businesProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" lazy-init="true">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<bean id="workflowManager" parent="workflowProxy" >
<property name="target">
<ref bean="workflowService"/>
</property>
</bean>
<bean id="businessManager" parent="businesProxy" >
<property name="target">
<ref bean="businessService"/>
</property>
</bean>
<bean id="workflowService" class="ht.workflow.test.WorkflowService">
<property name="workTabDAO">
<ref bean="workTabDAO" />
</property>
<property name="businessService">
<ref local="businessService" />
</property>
</bean>
<bean id="businessService" class="ht.business.test.BusinessService">
<property name="businessDAO">
<ref bean="businessDAO" />
</property>
</bean>
<bean id="workTabDAO" class="ht.workflow.dao.WorkTabDAO">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
<bean id="businessDAO" class="ht.business.dao.BusinessDAO">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
</beans>
目的: service A 用來向business表插入一條記錄 .
service B 調用service A 向business表插入一條記錄後,再向worktab表插入一條記錄。
若service A異常,事務復原,兩個表都沒有資料。
若service A正常執行,但在向worktab表插入資料時候異常,整個事務復原,兩個表仍然都沒有插入資料。
若service A正常執行,後面插入worktab也資料正常,則兩個表都插入資料。
題外話:當軟體開發基本上隻要熟悉操作手冊進行配置,當能力被熟練程度所代替,不知道我們還剩下多少創造力可以發揮了。