模仿NumberSeq写一个自动生成编码的功能。
起初只是简单通过读取数据库中最后的一个值来生成作为当前最大值,然后通过逻辑处理加1就生成了新的值。但是这之中就隐含了一个问题,线程的同步问题。由于多个客户端在执行,那么自动生成代码的方法也是多个线程在进行。这样就可能导致出现相同的号码(当一个线程读取数据库最大值还没有加1写入数据库的时候,另一个线程也读取到了当前数据库最大值,这时就会出现两个相同的号码在数据库中)。
那么这就涉及到了解决这个问题的方法,如何解决这个问题呢,起初我是想通过设置锁来控制线程同步。所以这就得需要用到全局变量,但是我找了好多资料,都没看见x++全局变量的设置,后来我看到了一个SysGlobalCache的类是全局变量设置,但我试了一下觉得很麻烦。我就开始从NumberSeq中入手,看看系统是怎么处理的。之后我就发现了系统用了一个talbe的setconnection方法,我还以为这个是给表上锁的意思,可是不对。
上面写了这么多其实都是问题解决的过程。那么我后来是怎么解决的呢。我发现其实给表上锁是通过table中的一个属性来设置的,将OccEnable(是否积极进行并发控制)设置为false,这样就可以在使用select forupdate的时候给表上锁,知道交易(transaction)结束。那么交易何时结束?在我的分步调试中发现是在最后一个commit结束的时候解锁。这就带来了问题,这个所会持续很长时间,这就对于系统的效率产生很大的影响。所以这里需要给table设置一个connection,就有之前的setconnection方法了。setconnection的参数是Connection类,只需要new一个Connection对象,再调用ttsbegin和ttscommit方法就好了,这个就和ttsbegin和ttscommit的系统关键字一样。
protected void updateJournalTablePosted(JournalTableMap _journalTable){ date tHCN_dTime; str tHCN_sDate, tHCN_sOld, tHCN_sTmp, tHCN_sNew; int tHCN_tmpNum, tHCN_oldNum, tHCN_count; HCN_InventJournalTable tHCN_InventJournalTable; InventJournalTable inventJournalTable; UserConnection userConnection; super(_journalTable); if (Common::isEnabled()) { select firstOnly inventJournalTable where inventJournalTable.RecId == _journalTable.RecId; if (inventJournalTable.JournalType != InventJournalType::Movement && inventJournalTable.JournalType != InventJournalType::LossProfit && inventJournalTable.JournalType != InventJournalType::Transfer) { return; } tHCN_dTime = systemDateGet(); //day 0 month 2 year 2 返回YYMM tHCN_sDate = date2str(tHCN_dTime, 0, 0, 0, 2, 0 ,2); userConnection = new UserConnection(); userConnection.ttsbegin(); //设置userconnection为了让tHCN_InventJournalTable独立于整个交易(Transaction) tHCN_InventJournalTable.setConnection(userConnection); //初始化代替从数据库中获取数据 HCN_InventJournalTable的occEnable设置为false //tHCN_InventJournalTable不是并发 forUpdate给tHCN_InventJournalTable上锁 select firstOnly forUpdate tHCN_InventJournalTable order by RefCode DESC where tHCN_InventJournalTable.RefCode like strfmt("%1%2%3", "抬头", date2str(tHCN_dTime, 0, 0, 0, 2, 0 ,2), "*"); if (!tHCN_InventJournalTable) { tHCN_sNew = "抬头" + tHCN_sDate + "0001"; } else { tHCN_sOld = tHCN_InventJournalTable.RefCode; tHCN_count = 0; //出库YYMM#### sub3,4取得YYMM tHCN_tmpNum = str2int(subStr(tHCN_sOld, 3, 4)); //出库YYMM#### sub7,4#### tHCN_tmpNum = str2int(subStr(tHCN_sOld, 7, 4)); tHCN_tmpNum++; tHCN_sTmp = strFmt("%1", tHCN_tmpNum); while (strLen(tHCN_sTmp) < 4) { tHCN_sTmp = strFmt("0%1", tHCN_sTmp); } tHCN_sNew = "抬头" + tHCN_sDate + tHCN_sTmp; } try { ttsBegin; select firstOnly forUpdate tHCN_InventJournalTable where tHCN_InventJournalTable.JournalId == _journalTable.JournalId; tHCN_InventJournalTable.RefCode = tHCN_sNew; if (tHCN_InventJournalTable && tHCN_InventJournalTable.JournalId == _journalTable.JournalId) { tHCN_InventJournalTable.update(); } else { tHCN_InventJournalTable.JournalId = _journalTable.JournalId; tHCN_InventJournalTable.insert(); } ttsCommit; } catch(Exception::Error) { userConnection.ttsabort(); // Call finalize to release sql connection, otherwise it's kept alive until GC collects. userConnection.finalize(); throw Exception::Error; } userConnection.ttscommit(); // Call finalize to release sql connection, otherwise it's kept alive until GC collects. userConnection.finalize(); }}