WorkFlow的事務(wù)回滾實(shí)現(xiàn)
Posted on 2006-03-02 21:03 killvin 閱讀(639) 評(píng)論(0) 編輯 收藏 所屬分類: osworkflowWorkflow Project 目前狀態(tài)
版本 0.11
已經(jīng)完成
1。完成了接口1 和接口2 的方法
2。完成接口3的默認(rèn)實(shí)現(xiàn)
3。完成事務(wù)回滾的實(shí)現(xiàn)方法-等待測(cè)試
未完成
1。接口3的注冊(cè)與實(shí)例化解決方案
2。應(yīng)用的并發(fā)訪問(wèn)問(wèn)題以及解決數(shù)據(jù)的臟讀問(wèn)題
3。與具體的某個(gè)應(yīng)用掛接并測(cè)試
-事務(wù)的回滾
OSWorkFlow的事務(wù)回滾是依靠WorkflowContext這個(gè)接口來(lái)實(shí)現(xiàn)的,在New出某個(gè)WorkFlow的時(shí)候需要聲明WorkflowContext的實(shí)現(xiàn)類,一般會(huì)采用uper.context = new GearWheelWorkFlowContext(_caller);方法
比如這樣實(shí)現(xiàn):
public GearWheelWorkFlow(String _caller)
{
super.context = new GearWheelWorkFlowContext(_caller);
}
但OSWorkFlow的WorkflowContext的默認(rèn)實(shí)現(xiàn)BasicWorkFlowContext中根本沒(méi)有實(shí)現(xiàn)setRollbackOnly方法,也就沒(méi)有了參考的可能
再看看這個(gè)接口的其他實(shí)現(xiàn)類也都是建立在JTA這樣的跨Session的事務(wù)服務(wù)上,比如它的EJB的實(shí)現(xiàn)也是要調(diào)用容器提供的JTA實(shí)現(xiàn)才行!而JTA的實(shí)現(xiàn)比如要JNDI到數(shù)據(jù)庫(kù)池,此時(shí)的應(yīng)用光JTA+JNDI就已經(jīng)宣布 -這樣的例子必須生存在應(yīng)用服務(wù)器的環(huán)境下!!
可是,我不死心,我記得Hibernate可以實(shí)現(xiàn)本地事務(wù),也就是依靠JDBC本身的事務(wù)處理能力,而要實(shí)現(xiàn)這樣的功能就需要在數(shù)據(jù)庫(kù)連接的獲取上下一些功夫,也就是要保證回滾的數(shù)據(jù)庫(kù)連接必須是獲取時(shí)的那個(gè)連接,而存儲(chǔ)連接就成了一個(gè)需要首先解決的問(wèn)題。
解決數(shù)據(jù)庫(kù)連接的存儲(chǔ)問(wèn)題
目前存儲(chǔ)數(shù)據(jù)庫(kù)連接除了依靠靜態(tài)類外,還有一個(gè)通用的方法ThreadLocal類,這樣獲取數(shù)據(jù)庫(kù)連接的方法寫成了如下的形式:
package com.company.common;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
public class DB2ConnectFactory
{
/**
* Logger for this class
*/
private static final Logger logger = Logger.getLogger(DB2ConnectFactory.class);
private static ThreadLocal threadLocal = new ThreadLocal();
//~
private Connection connect = null;
private Statement state = null;
private ResultSet result = null;
private boolean closeConnWhenDone = false;
//~
private String url = "jdbc:db2:WORKFLOW";
private String user = "";
private String password = "";
private String driverClassName = "COM.ibm.db2.jdbc.app.DB2Driver";
public DB2ConnectFactory() throws SQLException
{
this.init();
}
/**
* 獲取數(shù)據(jù)庫(kù)連接
* @return
* @throws SQLException
*/
public Connection getConn() throws SQLException
{
return (Connection)threadLocal.get();
}
/**
* 初始化數(shù)據(jù)庫(kù),并在緩沖中注冊(cè)數(shù)據(jù)庫(kù)連接
* @throws SQLException
*/
private void init() throws SQLException
{
try
{
// Get connect object
Class.forName(driverClassName);
closeConnWhenDone = true;
connect = DriverManager.getConnection(url, user, password);
state = connect.createStatement();
//Register the connection object in the threadlocal
threadLocal.set(connect);
}
catch (Exception e)
{
e.printStackTrace();
throw new SQLException(e.getMessage());
}
}
}
解決事務(wù)回滾
剛才說(shuō)了需要實(shí)現(xiàn)WorkflowContext接口
package com.company.engine.workflow;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.log4j.Logger;
import com.company.common.DB2ConnectFactory;
import com.opensymphony.workflow.WorkflowContext;
public class GearWheelWorkFlowContext implements WorkflowContext
{
/**
* Logger for this class
*/
private static final Logger logger = Logger.getLogger(GearWheelWorkFlowContext.class);
private static ThreadLocal threadLocal = new ThreadLocal();
// ~ Instance fields
// ////////////////////////////////////////////////////////
private String caller;
// ~ Constructors
// ///////////////////////////////////////////////////////////
public GearWheelWorkFlowContext(String caller)
{
this.caller = caller;
}
// ~ Methods
// ////////////////////////////////////////////////////////////////
public String getCaller()
{
return this.caller;
}
/**
* Tranaction : Set Roll back
* @throws SQLException
*/
public void setRollbackOnly()
{
Connection connect = null;
try
{
DB2ConnectFactory factory = new DB2ConnectFactory();
connect = factory.getConn();
if(connect != null) connect.rollback();
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
this.clostConnection(connect);
}
}
private void clostConnection(Connection connect)
{
try
{
if(connect != null) connect.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
總結(jié)
1。我們可以看到由于接口中setRollbackOnly沒(méi)有異常的聲明,方法中即使拋出了異常也要自己"忍了"!看來(lái)良好的接口聲明其實(shí)是非常重要的。
2。而且需要重載原來(lái)JDBCWorkflow 中的cleanup方法,將其中的代碼屏蔽掉!數(shù)據(jù)庫(kù)的關(guān)閉放在了setRollbackOnly訪訪的finally中,原因就是由于我們要統(tǒng)一的管理數(shù)據(jù)庫(kù)連接所引發(fā)的,我們不能夠在WorkFlowStore的每一個(gè)方法執(zhí)行完畢后就關(guān)閉連接,因?yàn)檫@樣的話你根本沒(méi)有了事務(wù)回滾的可能,所以此時(shí)的連接需要在WorkflowContext中來(lái)處理。
感觸
OSWorkFlow的實(shí)現(xiàn)方法并不是像網(wǎng)上所說(shuō)的那樣的優(yōu)秀和文雅,更像是一個(gè)未完成任務(wù)的"半成品",Heni被網(wǎng)上鼓吹為大牛,但一個(gè)不寫注釋和文檔的人,根本稱不上什么大牛!
OSWorkFlow更多的是實(shí)現(xiàn)了一個(gè)微內(nèi)核,而它的用戶模式是與OSUser這樣的框架耦合的(偶已經(jīng)將這樣的耦合打開(kāi)了,也就是接口3的定義),它的相關(guān)數(shù)據(jù)是與PropertySet框架耦合的(也就是接口2的定義),而且采用OSWorkFlow要經(jīng)過(guò)很原始的修改(比如我實(shí)現(xiàn)了DB2下的WorkFlowStore的實(shí)現(xiàn))。
不過(guò)也好即使以后不采用OSWorkFlow,自己實(shí)現(xiàn)一個(gè)這樣的引擎也應(yīng)該沒(méi)有什么問(wèn)題的,有時(shí)間了我倒是很想看看別的工作流的產(chǎn)品。
版本 0.11
已經(jīng)完成
1。完成了接口1 和接口2 的方法
2。完成接口3的默認(rèn)實(shí)現(xiàn)
3。完成事務(wù)回滾的實(shí)現(xiàn)方法-等待測(cè)試
未完成
1。接口3的注冊(cè)與實(shí)例化解決方案
2。應(yīng)用的并發(fā)訪問(wèn)問(wèn)題以及解決數(shù)據(jù)的臟讀問(wèn)題
3。與具體的某個(gè)應(yīng)用掛接并測(cè)試
-事務(wù)的回滾
OSWorkFlow的事務(wù)回滾是依靠WorkflowContext這個(gè)接口來(lái)實(shí)現(xiàn)的,在New出某個(gè)WorkFlow的時(shí)候需要聲明WorkflowContext的實(shí)現(xiàn)類,一般會(huì)采用uper.context = new GearWheelWorkFlowContext(_caller);方法
比如這樣實(shí)現(xiàn):
public GearWheelWorkFlow(String _caller)
{
super.context = new GearWheelWorkFlowContext(_caller);
}
但OSWorkFlow的WorkflowContext的默認(rèn)實(shí)現(xiàn)BasicWorkFlowContext中根本沒(méi)有實(shí)現(xiàn)setRollbackOnly方法,也就沒(méi)有了參考的可能
再看看這個(gè)接口的其他實(shí)現(xiàn)類也都是建立在JTA這樣的跨Session的事務(wù)服務(wù)上,比如它的EJB的實(shí)現(xiàn)也是要調(diào)用容器提供的JTA實(shí)現(xiàn)才行!而JTA的實(shí)現(xiàn)比如要JNDI到數(shù)據(jù)庫(kù)池,此時(shí)的應(yīng)用光JTA+JNDI就已經(jīng)宣布 -這樣的例子必須生存在應(yīng)用服務(wù)器的環(huán)境下!!
可是,我不死心,我記得Hibernate可以實(shí)現(xiàn)本地事務(wù),也就是依靠JDBC本身的事務(wù)處理能力,而要實(shí)現(xiàn)這樣的功能就需要在數(shù)據(jù)庫(kù)連接的獲取上下一些功夫,也就是要保證回滾的數(shù)據(jù)庫(kù)連接必須是獲取時(shí)的那個(gè)連接,而存儲(chǔ)連接就成了一個(gè)需要首先解決的問(wèn)題。
解決數(shù)據(jù)庫(kù)連接的存儲(chǔ)問(wèn)題
目前存儲(chǔ)數(shù)據(jù)庫(kù)連接除了依靠靜態(tài)類外,還有一個(gè)通用的方法ThreadLocal類,這樣獲取數(shù)據(jù)庫(kù)連接的方法寫成了如下的形式:
package com.company.common;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
public class DB2ConnectFactory
{
/**
* Logger for this class
*/
private static final Logger logger = Logger.getLogger(DB2ConnectFactory.class);
private static ThreadLocal threadLocal = new ThreadLocal();
//~
private Connection connect = null;
private Statement state = null;
private ResultSet result = null;
private boolean closeConnWhenDone = false;
//~
private String url = "jdbc:db2:WORKFLOW";
private String user = "";
private String password = "";
private String driverClassName = "COM.ibm.db2.jdbc.app.DB2Driver";
public DB2ConnectFactory() throws SQLException
{
this.init();
}
/**
* 獲取數(shù)據(jù)庫(kù)連接
* @return
* @throws SQLException
*/
public Connection getConn() throws SQLException
{
return (Connection)threadLocal.get();
}
/**
* 初始化數(shù)據(jù)庫(kù),并在緩沖中注冊(cè)數(shù)據(jù)庫(kù)連接
* @throws SQLException
*/
private void init() throws SQLException
{
try
{
// Get connect object
Class.forName(driverClassName);
closeConnWhenDone = true;
connect = DriverManager.getConnection(url, user, password);
state = connect.createStatement();
//Register the connection object in the threadlocal
threadLocal.set(connect);
}
catch (Exception e)
{
e.printStackTrace();
throw new SQLException(e.getMessage());
}
}
}
解決事務(wù)回滾
剛才說(shuō)了需要實(shí)現(xiàn)WorkflowContext接口
package com.company.engine.workflow;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.log4j.Logger;
import com.company.common.DB2ConnectFactory;
import com.opensymphony.workflow.WorkflowContext;
public class GearWheelWorkFlowContext implements WorkflowContext
{
/**
* Logger for this class
*/
private static final Logger logger = Logger.getLogger(GearWheelWorkFlowContext.class);
private static ThreadLocal threadLocal = new ThreadLocal();
// ~ Instance fields
// ////////////////////////////////////////////////////////
private String caller;
// ~ Constructors
// ///////////////////////////////////////////////////////////
public GearWheelWorkFlowContext(String caller)
{
this.caller = caller;
}
// ~ Methods
// ////////////////////////////////////////////////////////////////
public String getCaller()
{
return this.caller;
}
/**
* Tranaction : Set Roll back
* @throws SQLException
*/
public void setRollbackOnly()
{
Connection connect = null;
try
{
DB2ConnectFactory factory = new DB2ConnectFactory();
connect = factory.getConn();
if(connect != null) connect.rollback();
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
this.clostConnection(connect);
}
}
private void clostConnection(Connection connect)
{
try
{
if(connect != null) connect.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
總結(jié)
1。我們可以看到由于接口中setRollbackOnly沒(méi)有異常的聲明,方法中即使拋出了異常也要自己"忍了"!看來(lái)良好的接口聲明其實(shí)是非常重要的。
2。而且需要重載原來(lái)JDBCWorkflow 中的cleanup方法,將其中的代碼屏蔽掉!數(shù)據(jù)庫(kù)的關(guān)閉放在了setRollbackOnly訪訪的finally中,原因就是由于我們要統(tǒng)一的管理數(shù)據(jù)庫(kù)連接所引發(fā)的,我們不能夠在WorkFlowStore的每一個(gè)方法執(zhí)行完畢后就關(guān)閉連接,因?yàn)檫@樣的話你根本沒(méi)有了事務(wù)回滾的可能,所以此時(shí)的連接需要在WorkflowContext中來(lái)處理。
感觸
OSWorkFlow的實(shí)現(xiàn)方法并不是像網(wǎng)上所說(shuō)的那樣的優(yōu)秀和文雅,更像是一個(gè)未完成任務(wù)的"半成品",Heni被網(wǎng)上鼓吹為大牛,但一個(gè)不寫注釋和文檔的人,根本稱不上什么大牛!
OSWorkFlow更多的是實(shí)現(xiàn)了一個(gè)微內(nèi)核,而它的用戶模式是與OSUser這樣的框架耦合的(偶已經(jīng)將這樣的耦合打開(kāi)了,也就是接口3的定義),它的相關(guān)數(shù)據(jù)是與PropertySet框架耦合的(也就是接口2的定義),而且采用OSWorkFlow要經(jīng)過(guò)很原始的修改(比如我實(shí)現(xiàn)了DB2下的WorkFlowStore的實(shí)現(xiàn))。
不過(guò)也好即使以后不采用OSWorkFlow,自己實(shí)現(xiàn)一個(gè)這樣的引擎也應(yīng)該沒(méi)有什么問(wèn)題的,有時(shí)間了我倒是很想看看別的工作流的產(chǎn)品。