事務不應該由dao管理,而應該由service管理
最重要的是如下四個類
DataSource :數據庫的Connection連接工廠
DataSourceUtils:
參與同一個事務的多個dao實際上應該是共享同一個conn的。
DataSourceUtils.getConnection(dataSource)取得當前ThreadLocal的conn,如果沒有從dataSource創建一個。
DataSourceUtils.releaseConnection(conn, dataSource)未必真正關閉連接。
DataSourceTransactionManager
TransactionProxyFactoryBean;攔截具體業務對象方法調用,中間根據DataSourceTransactionManager設置進行事務管理
文筆不行,說不明白,舉個例子:
dao1{
method(){
conn= DataSourceUtils.getConnection(dataSource);
...........
DataSourceUtils.releaseConnection(conn, dataSource);
}
}
dao2{
method(){
conn= DataSourceUtils.getConnection(dataSource);
...........
DataSourceUtils.releaseConnection(conn, dataSource);
}
}
service{ method(); }
serviceImp{
method(){
dao1.method();
dao2.method();
}
}
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource">
<ref local="dataSource" />
</property>
</bean>
<bean id="service"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="target">
<ref local="serviceImp" />
</property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
分析:
當調用service.method()時,開始TransactionProxyFactoryBean攔截此方法指定當前線程需要事務,然后調用dao1.method(),
調用conn= DataSourceUtils.getConnection(dataSource)
判斷當前線程還沒有conn則創建一個,因為此時線程需要事務所以conn.setAutoCommit(false),執行數據庫作,
然后DataSourceUtils.releaseConnection(conn, dataSource),判斷當前線程需要事務所以不真正關閉連接繼續,dao1.method()返回。
調用dao2.method(),調用conn= DataSourceUtils.getConnection(dataSource)判斷當前線程有一個conn就返回這個conn,(此時dao1.method()和dao2.method()已經共用了這個conn),執行數據庫操作,然后DataSourceUtils.releaseConnection(conn, dataSource),判斷當前線程需要事務
所以不真正關閉連接繼續,dao2.method()返回。service.method()返回,TransactionProxyFactoryBean攔截取得當前線程連接提交事務,關閉清除連接。這樣兩個dao就參與到了一個事務當中。如果service.method()拋出異常,則TransactionProxyFactoryBean在service.method()返回時攔截取得當前線程連接回滾事務,關閉清除連接。
不知道猜得對不對