﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-J++ = Java + ?-随笔分类-osworkflow</title><link>http://www.blogjava.net/killvin/category/8035.html</link><description /><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 08:46:46 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 08:46:46 GMT</pubDate><ttl>60</ttl><item><title>OSWorkflow深入分析 － 重新定义Configuration接口 </title><link>http://www.blogjava.net/killvin/archive/2006/03/02/33314.html</link><dc:creator>killvin</dc:creator><author>killvin</author><pubDate>Thu, 02 Mar 2006 13:04:00 GMT</pubDate><guid>http://www.blogjava.net/killvin/archive/2006/03/02/33314.html</guid><description><![CDATA[<P>在OSWorkflow中最让人恼火的就是它的接口定义！我会就这些接口的混乱展开一系列的分析，今天先说说Configuration接口</P>
<P>偶继承了它的Configuration接口</P>
<P>import com.company.engine.workflow.store.IWorkFlowStore;<BR>import com.opensymphony.workflow.StoreException;<BR>import com.opensymphony.workflow.config.Configuration;<BR>import com.opensymphony.workflow.spi.WorkflowStore;</P>
<P>public interface IConfiguration extends Configuration<BR>{<BR>&nbsp;/**<BR>&nbsp; * @deprecated getIWorkflowStore()<BR>&nbsp; */<BR>&nbsp;&nbsp;&nbsp; <STRONG>WorkflowStore getWorkflowStore() throws StoreException;<BR></STRONG>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; /**<BR>&nbsp;&nbsp;&nbsp;&nbsp; * return WorkFlowStore which implements the interface of IWorkFlowStore <BR>&nbsp;&nbsp;&nbsp;&nbsp; * @return<BR>&nbsp;&nbsp;&nbsp;&nbsp; * @throws StoreException<BR>&nbsp;&nbsp;&nbsp;&nbsp; */<BR>&nbsp;&nbsp;&nbsp; <STRONG>IWorkFlowStore getIWorkflowStore() throws StoreException;</STRONG><BR>&nbsp;&nbsp;&nbsp; <BR>}</P>
<P>你可能奇怪我为何要继承它的接口（肯定是Bad smell），原因如下，</P>
<P><STRONG>IWorkFlowStore </STRONG>接口定义</P>
<P>import com.opensymphony.workflow.StoreException;<BR>import com.opensymphony.workflow.spi.Step;<BR>import com.opensymphony.workflow.spi.WorkflowEntry;<BR>import com.opensymphony.workflow.spi.WorkflowStore;</P>
<P>public interface IWorkFlowStore extends WorkflowStore<BR>{<BR>&nbsp;<BR>&nbsp;public Step createCurrentStep(WorkflowEntry _entry , Step _step) throws StoreException;</P>
<P>}</P>
<P><STRONG>WorkflowStore</STRONG>接口定义</P>
<P>&nbsp;&nbsp;&nbsp; /**<BR>&nbsp;&nbsp;&nbsp;&nbsp; * Persists a step with the given parameters.<BR>&nbsp;&nbsp;&nbsp;&nbsp; *<BR>&nbsp;&nbsp;&nbsp;&nbsp; * @param entryId The workflow instance id.<BR>&nbsp;&nbsp;&nbsp;&nbsp; * @param stepId the ID of the workflow step associated with this new<BR>&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Step (not to be confused with the step primary key)<BR>&nbsp;&nbsp;&nbsp;&nbsp; * @param owner the owner of the step<BR>&nbsp;&nbsp;&nbsp;&nbsp; * @param startDate the start date of the step<BR>&nbsp;&nbsp;&nbsp;&nbsp; * @param status the status of the step<BR>&nbsp;&nbsp;&nbsp;&nbsp; * @param previousIds the previous step IDs<BR>&nbsp;&nbsp;&nbsp;&nbsp; * @return a representation of the workflow step persisted<BR>&nbsp;&nbsp;&nbsp;&nbsp; */<BR>&nbsp;&nbsp;&nbsp; public Step createCurrentStep(long entryId, int stepId, String owner, Date startDate, Date dueDate, String status, long[] previousIds) throws StoreException;<BR></P>
<P>看到了吧？</P>
<P>其实我只是希望在createCurrentStep时按照OO的方法执行，而不是传递那些"Bad Smell"的参数，而OSWorkflow中的WorkflowStore是需要Configuration来获取的，此时为了增加一个看似合理的方法，需要分别继承Configuration与WorkflowStore；这还没有完，你需要实现一个Configuration实现！！</P>
<P>import com.company.engine.workflow.store.IWorkFlowStore;<BR>import com.opensymphony.workflow.StoreException;<BR>import com.opensymphony.workflow.config.DefaultConfiguration;<BR>import com.opensymphony.workflow.spi.WorkflowStore;</P>
<P>public class <STRONG>DefaultIConfiguration</STRONG> extends <STRONG>DefaultConfiguration</STRONG> implements <STRONG>IConfiguration</STRONG><BR>{<BR>&nbsp;<BR><STRONG>&nbsp;&nbsp;&nbsp; public static DefaultIConfiguration INSTANCE = new DefaultIConfiguration();<BR>&nbsp;&nbsp;&nbsp; private transient IWorkFlowStore store = null;</STRONG></P>
<P>&nbsp;/**<BR>&nbsp; * @deprecated getIWorkflowStore()<BR>&nbsp; */<BR>&nbsp;public WorkflowStore getWorkflowStore() throws StoreException<BR>&nbsp;{<BR>&nbsp;&nbsp;return null;<BR>&nbsp;}</P>
<P>&nbsp;public IWorkFlowStore getIWorkflowStore() throws StoreException<BR>&nbsp;{<BR>&nbsp;&nbsp;if (store == null)<BR>&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;String clazz = getPersistence();</P>
<P>&nbsp;&nbsp;&nbsp;try<BR>&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;store = (IWorkFlowStore) Class.forName(clazz).newInstance();<BR>&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;catch (Exception ex)<BR>&nbsp;&nbsp;&nbsp;{<BR>&nbsp;&nbsp;&nbsp;&nbsp;throw new StoreException("Error creating store", ex);<BR>&nbsp;&nbsp;&nbsp;}</P>
<P>&nbsp;&nbsp;&nbsp;store.init(getPersistenceArgs());<BR>&nbsp;&nbsp;}</P>
<P>&nbsp;&nbsp;return store;<BR>&nbsp;}</P>
<P>}<BR></P>
<P>总结</P>
<P>1。OSWorkflow与WorkflowStore接口的关系比较的微妙，它需要借助于Configuration接口的实现来获取到实际的WorkflowStore对象。</P>
<P>2。由于这样的一种微妙关系，对WorkflowStore接口的扩展必将连带着需要扩展Configuration接口，而产生这样的"果冻效应"的罪魁祸首就是由于WorkflowStore接口与Configuration接口耦合的太紧。</P>
<P>3。OSWorkflow并没有很好的遵守OO的设计规则，尤其在它的参数传递上，非常的差！</P><img src ="http://www.blogjava.net/killvin/aggbug/33314.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killvin/" target="_blank">killvin</a> 2006-03-02 21:04 <a href="http://www.blogjava.net/killvin/archive/2006/03/02/33314.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>workflow接口划分 </title><link>http://www.blogjava.net/killvin/archive/2006/03/02/33312.html</link><dc:creator>killvin</dc:creator><author>killvin</author><pubDate>Thu, 02 Mar 2006 13:03:00 GMT</pubDate><guid>http://www.blogjava.net/killvin/archive/2006/03/02/33312.html</guid><description><![CDATA[<DIV class=content>workflow接口划分<BR><BR>1。应用接口 Application Interface<BR>－－interface1 工作流自身提供的服务接口<BR>－－interface2 工作流与应用之间的接口（主要是提供相关数据的调用接口）<BR><BR>2。扩展接口 PlugIn Interface<BR>－－interface3 工作流与组织机构之间的接口<BR>－－interface4 工作流与其他工作流之间的接口<BR><BR>将接口划分成应用接口与扩展接口主要是依据工作流与相关应用的调用关系，比如工作流与组织机构之间，是工作流调用组织机构中的人员信息，所以主动者是WORKFLOW、被动方是组织机构，所以应该采用扩展接口来实现<BR><BR>在扩展接口上应该采用Adapter模式，从而使工作流不局限于某个特定的实现<BR><BR>目前的进展<BR>0。Application Interface接口已经基本实现了<BR>PlugIn Interface接口目前基本完工，但OSWorkflow的实现实在是非常的丑陋，需要更改的地方太多，而且对于Interface3不可以使用它采用的User / Group模型（而且它使用了OSUser这个框架，对于多数的应用程序基本可以说不适合，而且它的User类竟然是Final ?!而且我发现它的很多类的属性都是Protected！也就是说除了他们自己根本没有办法扩展，即使扩展也是很丑陋的方式）<BR><BR>1。现在最大的问题是它的WorkStore接口的扩展，我采用DB2的方式实现了它的接口，但这样的方式会与DB2绑定在一起，如果自己写实现就要根据不同的DB采用不同的SQL语言－也就是不同的方言策略？！而且考虑到性能估计不是什么好主意，看来明天需要更换成HibernateWorkStore的形式，这样工作流的持久层接口将工作在Hibernate之上，看来很完美的解决了这个问题。<BR><BR>2。而且我扩展了它的PropertySet，使其不再依靠JNDI寻找DataSource，而是通过嵌入在程序内部采用JDBC的形式寻找数据库连接，这样我就不必为了验证一个问题去建立那该死的数据库缓冲池了（而且JNDI的形式也就不可避免的要用到容器，太重了！）<BR><BR>3。我编写了UserGroupCondition的实现类，这个类的作用就是调用Interface3的方法，从而判断某个用户是否属于某个组（现在的做法是让WorkStore实现Interface3的偷懒办法，但很乱，看来还是要写一个Adapter去实现interface3才对！）<BR><BR>4。目前工作流引擎的工厂类已经实现完工并测试通过。<BR><BR><BR>用了近一个月的时间完成了这些工作，看起来很少但是基本上大量的时间花费在熟悉工作流规范、WFMC标准、以及学习和扩展OSWorkflow接口上，不过对OSWorkflow的实现基本上掌握了，如果抛开OSWorkflow自己也可以采用自己的方式去实现，或者会考虑使用Spring的方式（Interface3的Adapter不行就采用Spring实现）。<BR><BR>BTW:<BR>OSWorkflow的实现其实比较的丑陋！而且编码根本没有什么规范，接口的定义也是天马行空，看来Heni除了他的大嘴外应该好好的提高自己的技术修养。－实在不敢恭维这位"大师"的编码水平！<BR></DIV><img src ="http://www.blogjava.net/killvin/aggbug/33312.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killvin/" target="_blank">killvin</a> 2006-03-02 21:03 <a href="http://www.blogjava.net/killvin/archive/2006/03/02/33312.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>WorkFlow的事务回滚实现 </title><link>http://www.blogjava.net/killvin/archive/2006/03/02/33313.html</link><dc:creator>killvin</dc:creator><author>killvin</author><pubDate>Thu, 02 Mar 2006 13:03:00 GMT</pubDate><guid>http://www.blogjava.net/killvin/archive/2006/03/02/33313.html</guid><description><![CDATA[Workflow Project 目前状态<BR>版本 0.11<BR><BR>已经完成<BR>1。完成了接口1 和接口2 的方法<BR>2。完成接口3的默认实现<BR>3。完成事务回滚的实现方法－等待测试<BR><BR>未完成<BR>1。接口3的注册与实例化解决方案<BR>2。应用的并发访问问题以及解决数据的脏读问题<BR>3。与具体的某个应用挂接并测试<BR><BR><BR>－事务的回滚<BR>OSWorkFlow的事务回滚是依靠WorkflowContext这个接口来实现的，在New出某个WorkFlow的时候需要声明WorkflowContext的实现类，一般会采用uper.context = new GearWheelWorkFlowContext(_caller);方法<BR>比如这样实现：<BR><BR>public GearWheelWorkFlow(String _caller)<BR>{<BR>super.context = new GearWheelWorkFlowContext(_caller);<BR>}<BR><BR>但OSWorkFlow的WorkflowContext的默认实现BasicWorkFlowContext中根本没有实现setRollbackOnly方法，也就没有了参考的可能<BR><BR>再看看这个接口的其他实现类也都是建立在JTA这样的跨Session的事务服务上，比如它的EJB的实现也是要调用容器提供的JTA实现才行！而JTA的实现比如要JNDI到数据库池，此时的应用光JTA+JNDI就已经宣布 －这样的例子必须生存在应用服务器的环境下！！<BR><BR>可是，我不死心，我记得Hibernate可以实现本地事务，也就是依靠JDBC本身的事务处理能力，而要实现这样的功能就需要在数据库连接的获取上下一些功夫，也就是要保证回滚的数据库连接必须是获取时的那个连接，而存储连接就成了一个需要首先解决的问题。<BR><BR>解决数据库连接的存储问题<BR>目前存储数据库连接除了依靠静态类外，还有一个通用的方法ThreadLocal类，这样获取数据库连接的方法写成了如下的形式：<BR><BR>package com.company.common;<BR>import java.sql.Connection;<BR>import java.sql.DriverManager;<BR>import java.sql.ResultSet;<BR>import java.sql.SQLException;<BR>import java.sql.Statement;<BR>import java.util.Collections;<BR>import java.util.HashMap;<BR>import java.util.Map;<BR>import org.apache.log4j.Logger;<BR>public class DB2ConnectFactory<BR>{<BR>/**<BR>* Logger for this class<BR>*/<BR>private static final Logger logger = Logger.getLogger(DB2ConnectFactory.class);<BR>private static ThreadLocal threadLocal = new ThreadLocal();<BR>//~<BR>private Connection connect = null;<BR>private Statement state = null;<BR>private ResultSet result = null;<BR>private boolean closeConnWhenDone = false;<BR>//~<BR>private String url = "jdbc:db2:WORKFLOW";<BR>private String user = "";<BR>private String password = "";<BR>private String driverClassName = "COM.ibm.db2.jdbc.app.DB2Driver";<BR><BR>public DB2ConnectFactory() throws SQLException<BR>{<BR>this.init();<BR>}<BR><BR>/**<BR>* 获取数据库连接<BR>* @return<BR>* @throws SQLException<BR>*/<BR>public Connection getConn() throws SQLException<BR>{<BR>return (Connection)threadLocal.get();<BR>}<BR><BR>/**<BR>* 初始化数据库,并在缓冲中注册数据库连接<BR>* @throws SQLException<BR>*/<BR>private void init() throws SQLException<BR>{<BR>try<BR>{<BR>// Get connect object<BR>Class.forName(driverClassName);<BR>closeConnWhenDone = true;<BR><BR>connect = DriverManager.getConnection(url, user, password);<BR>state = connect.createStatement();<BR><BR>//Register the connection object in the threadlocal<BR>threadLocal.set(connect);<BR>}<BR>catch (Exception e)<BR>{<BR>e.printStackTrace();<BR>throw new SQLException(e.getMessage());<BR>}<BR>}<BR><BR>}<BR><BR>解决事务回滚<BR>刚才说了需要实现WorkflowContext接口<BR>package com.company.engine.workflow;<BR>import java.sql.Connection;<BR>import java.sql.SQLException;<BR>import org.apache.log4j.Logger;<BR>import com.company.common.DB2ConnectFactory;<BR>import com.opensymphony.workflow.WorkflowContext;<BR>public class GearWheelWorkFlowContext implements WorkflowContext<BR>{<BR>/**<BR>* Logger for this class<BR>*/<BR>private static final Logger logger = Logger.getLogger(GearWheelWorkFlowContext.class);<BR><BR>private static ThreadLocal threadLocal = new ThreadLocal();<BR><BR>// ~ Instance fields<BR>// ////////////////////////////////////////////////////////<BR>private String caller;<BR>// ~ Constructors<BR>// ///////////////////////////////////////////////////////////<BR>public GearWheelWorkFlowContext(String caller)<BR>{<BR>this.caller = caller;<BR>}<BR>// ~ Methods<BR>// ////////////////////////////////////////////////////////////////<BR>public String getCaller()<BR>{<BR>return this.caller;<BR>}<BR>/**<BR>* Tranaction : Set Roll back<BR>* @throws SQLException <BR>*/<BR>public void setRollbackOnly()<BR>{<BR>Connection connect = null;<BR>try<BR>{<BR>DB2ConnectFactory factory = new DB2ConnectFactory();<BR>connect = factory.getConn();<BR>if(connect != null) connect.rollback();<BR>}<BR>catch (Exception e)<BR>{<BR>e.printStackTrace();<BR>}<BR>finally<BR>{<BR>this.clostConnection(connect);<BR>}<BR>}<BR><BR>private void clostConnection(Connection connect)<BR>{<BR>try<BR>{<BR>if(connect != null) connect.close();<BR>}<BR>catch (Exception e)<BR>{<BR>e.printStackTrace();<BR>}<BR>}<BR>}<BR><BR>总结<BR>1。我们可以看到由于接口中setRollbackOnly没有异常的声明，方法中即使抛出了异常也要自己"忍了"！看来良好的接口声明其实是非常重要的。<BR><BR>2。而且需要重载原来JDBCWorkflow 中的cleanup方法，将其中的代码屏蔽掉！数据库的关闭放在了setRollbackOnly访访的finally中，原因就是由于我们要统一的管理数据库连接所引发的，我们不能够在WorkFlowStore的每一个方法执行完毕后就关闭连接，因为这样的话你根本没有了事务回滚的可能，所以此时的连接需要在WorkflowContext中来处理。<BR><BR><BR>感触<BR>OSWorkFlow的实现方法并不是像网上所说的那样的优秀和文雅，更像是一个未完成任务的"半成品"，Heni被网上鼓吹为大牛，但一个不写注释和文档的人，根本称不上什么大牛！<BR>OSWorkFlow更多的是实现了一个微内核，而它的用户模式是与OSUser这样的框架耦合的（偶已经将这样的耦合打开了，也就是接口3的定义），它的相关数据是与PropertySet框架耦合的（也就是接口2的定义），而且采用OSWorkFlow要经过很原始的修改（比如我实现了DB2下的WorkFlowStore的实现）。<BR><BR>不过也好即使以后不采用OSWorkFlow，自己实现一个这样的引擎也应该没有什么问题的，有时间了我倒是很想看看别的工作流的产品。<img src ="http://www.blogjava.net/killvin/aggbug/33313.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killvin/" target="_blank">killvin</a> 2006-03-02 21:03 <a href="http://www.blogjava.net/killvin/archive/2006/03/02/33313.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>OSWorkflow你让我把数据库关闭写在哪里！ </title><link>http://www.blogjava.net/killvin/archive/2006/03/02/33311.html</link><dc:creator>killvin</dc:creator><author>killvin</author><pubDate>Thu, 02 Mar 2006 13:02:00 GMT</pubDate><guid>http://www.blogjava.net/killvin/archive/2006/03/02/33311.html</guid><description><![CDATA[<P>在Workflow事务回滚中遇到了问题，是这样的</P>
<P>DB2ConnectFactory 中getConn方法<BR>/**<BR>* 获取数据库连接<BR>* @return<BR>* @throws SQLException<BR>*/<BR>public Connection getConn() throws SQLException<BR>{<BR>Object obj = threadLocal.get();<BR>if(obj == null)<BR>{<BR>this.initFactoryStack();<BR>}else<BR>{<BR>connect = (Connection)obj;<BR>}<BR>connect.setAutoCommit(false); //事务的回滚必须建立在将Commit状态为False下，默认是true<BR>logger.debug("Get connect from factory - " + connect.hashCode());<BR>return connect;<BR>}</P>
<P></P>
<P>AbstractWorkflow 的doAction()方法</P>
<P><BR>try {<BR>//transition the workflow, if it wasn't explicitly finished, check for an implicit finish<BR>if (!transitionWorkflow(entry, currentSteps, store, wf, action, transientVars, inputs, ps)) {<BR>checkImplicitFinish(id);<BR>}<BR>} catch (WorkflowException e) {<BR>context.setRollbackOnly(); // 这里调用WorkContext对象的setRollbackOnly()方法，执行事务的回滚<BR>throw e;<BR>}</P>
<P></P>
<P>GearWheelWorkFlowContext 的setRollbackOnly方法<BR>/**<BR>* Tranaction : Set Roll back<BR>* @throws SQLException <BR>*/<BR>public void setRollbackOnly()<BR>{<BR>logger.debug("Context execute setRollbackOnly() !!");<BR>Connection connect = null;<BR>try<BR>{<BR>DB2ConnectFactory factory = new DB2ConnectFactory();<BR>connect = factory.getConn();<BR>logger.debug("Context get connect " + connect.hashCode());</P>
<P>if(connect != null) connect.rollback();<BR>}<BR>catch (Exception e)<BR>{<BR>e.printStackTrace();<BR>}<BR>finally<BR>{<BR>this.clostConnection(connect); //这里将关闭数据库连接<BR>}<BR>}</P>
<P><BR>可是这是"异常"情况下的处理流程，如果正常执行呢？<BR>刚开始我想写在CleanUp()方法里，但又一想不行，因为正常执行的流程需要做两个工作<BR>1。将Commit状态更新为true,并提交连接<BR>2。关闭数据库连接</P>
<P><BR>关键就是关闭数据库的连接在哪里写？！现在写在CleanUp()不合适，因为每一个WorkStore的方法都要默认（程序已经写死了,我可不想重载它的所有的方法！！）的关闭数据库连接！<BR>仔细的分析了一下，其实有两个方法可以做到<BR>1。编写Proxy类<BR>2。重载所有AbstractWorkflow中设计到事务的方法，（本来可以重载transitionWorkflow但是方法的类型却为private?!）在它的方法下增加一个"提交"的方法。比如这样</P>
<P>try {<BR>//transition the workflow, if it wasn't explicitly finished, check for an implicit finish<BR>if (!transitionWorkflow(entry, currentSteps, store, wf, action, transientVars, inputs, ps))<BR>{<BR>checkImplicitFinish(id);<BR>}</P>
<P>dosubmit();</P>
<P>} catch (WorkflowException e) {<BR>context.setRollbackOnly(); // 这里调用WorkContext对象的setRollbackOnly()方法，执行事务的回滚<BR>throw e;<BR>}</P>
<P>可以看到方法2比较"烂"，看来下一步即使编写方法1的实现</P><BR><img src ="http://www.blogjava.net/killvin/aggbug/33311.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killvin/" target="_blank">killvin</a> 2006-03-02 21:02 <a href="http://www.blogjava.net/killvin/archive/2006/03/02/33311.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDBCWorkflow不支持Sequence </title><link>http://www.blogjava.net/killvin/archive/2006/03/02/33310.html</link><dc:creator>killvin</dc:creator><author>killvin</author><pubDate>Thu, 02 Mar 2006 13:01:00 GMT</pubDate><guid>http://www.blogjava.net/killvin/archive/2006/03/02/33310.html</guid><description><![CDATA[<P>早上的时间被该死的WorkflwoStore里的主键生成策略（"主键生成策略"来源于Hibernate文档），该死的Sequence,从文档资料上看到DB2是支持Sequence的，按照db2的文档我执行了如下的语句：<BR>create sequence seq_os_wfentry start with 10 increment by 10;<BR>create sequence seq_os_currentsteps;<BR>执行-ok</P>
<P>可是我以前不太了解Sequence的概念，这片资料倒是很有价值<BR><A href="http://www-128.ibm.com/developerworks/db2/library/techarticle/dm-0407zhang/"><FONT color=#000080>http://www-128.ibm.com/developerworks/db2/library/techarticle/dm-0407zhang/</FONT></A><BR>不过我以为查询Sequence就只需要执行SELECT NEXT VALUE FOR seq_os_wfentry 就ok了，可是谁知道总是报错？！在比较仔细的看了这片文章之后发现，其实根本就无法执行这条SQL！而需要这样<BR>INSERT INTO EMPLOYEE ( SERIALNUMBER, FIRSTNAME, LASTNAME, <BR>SALARY) VALUES(NEXTVAL FOR EMPSERIAL, 'Martin', 'Wong', 1000.00)</P>
<P>可是看看JDBCWorkflowStore的实现，这里是JDBCWorkflowStore的主键生成策略！<BR>protected long getNextEntrySequence(Connection c) throws SQLException {<BR>if (log.isDebugEnabled()) {<BR>log.debug("Executing SQL statement: " + entrySequence);<BR>}</P>
<P>PreparedStatement stmt = null;<BR>ResultSet rset = null;</P>
<P>try {<BR>stmt = c.prepareStatement(entrySequence);<BR>rset = stmt.executeQuery();<BR>rset.next();</P>
<P>long id = rset.getLong(1);</P>
<P>return id;<BR>} finally {<BR>cleanup(null, stmt, rset);<BR>}<BR>}</P>
<P>c.prepareStatement(entrySequence) － 其实执行了一条SQL语句，所以看来JDBCWorkflow根本不支持Sequence生成策略！！</P>
<P>该死的实现方式，看来我要重载其实现方式，不过说真的JDBCWorkflow的编码人员其实水平不匝地！</P><img src ="http://www.blogjava.net/killvin/aggbug/33310.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killvin/" target="_blank">killvin</a> 2006-03-02 21:01 <a href="http://www.blogjava.net/killvin/archive/2006/03/02/33310.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>小心OSPropertySet － PropertySet </title><link>http://www.blogjava.net/killvin/archive/2006/03/02/33309.html</link><dc:creator>killvin</dc:creator><author>killvin</author><pubDate>Thu, 02 Mar 2006 13:00:00 GMT</pubDate><guid>http://www.blogjava.net/killvin/archive/2006/03/02/33309.html</guid><description><![CDATA[OSPropertySet的最新版本是1.3 Date: 9/22/2003 ，不要使用OSWorkflow中自带的OSPropertySet.jar ，主要是因为它的版本为propertyset-1.3-21Apr04，甚至里面的接口PropertySet竟然私自更换了（这个版本的remove()方法是抽象的，而新版本已经将这个方法命名为Public!!）<BR><img src ="http://www.blogjava.net/killvin/aggbug/33309.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killvin/" target="_blank">killvin</a> 2006-03-02 21:00 <a href="http://www.blogjava.net/killvin/archive/2006/03/02/33309.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>