工廠方法模式
以可移植的、可擴(kuò)展的方式來生成流水號EJB應(yīng)用中的一個難點(diǎn)。 現(xiàn)在比較成熟的流水號生成策略有全局唯一標(biāo)識(即UUID)和使用數(shù)據(jù)庫內(nèi)置流水號生成策略。全局唯一標(biāo)識有單件模式、根據(jù)網(wǎng)絡(luò)標(biāo)識(Mac地址+IP+JVM唯一對象標(biāo)識)等策略。不同的數(shù)據(jù)庫也有不同的流水號生成策略:例如Oracle采用內(nèi)置流水號產(chǎn)生機(jī)制,SQL Server則采用Identity機(jī)制。這給我們帶來方便的同時也使得應(yīng)用程序在不同系統(tǒng)之間移植變得很麻煩。我采用工廠方法模式解決這個問題。
結(jié)構(gòu)圖

我們首先定義一個基類接口,它定義了各種唯一序列生成器的共同的方法。
abstract public interface SequenceCreator {
abstract public String getSequenceId(String aId);
abstract public Integer getSequenceAsInt(String aId);
}
兩個函數(shù)的參數(shù)aId是不同流水號生成標(biāo)識。getSequenceId是產(chǎn)生以字符串形式返回的流水號,getSequenceAsInt是以整形形式返回流水號。為了防止無謂的重復(fù),下面的實例中我們將只寫各個方法的getSequenceId實現(xiàn)。
(1)我們首先看SQLSequenceCreator的實現(xiàn)代碼
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection con = java.sql.DriverManager.getConnection("jdbc:odbc:DNSEJB");
CallableStatement cs = con.prepareCall("{call SetIndex(?,?,?)}");
cs.registerOutParameter(2,Types.VARCHAR);
cs.setString(1,aId);
cs.setInt(3,10);
cs.executeUpdate();
String str= cs.getString(2);
return str.substring(aId.length(), str.length());
我們是調(diào)用我們自定義的存儲過程來生成流水號的,存儲過程的代碼請參看代碼。
(2)Oracle的實現(xiàn)代碼
String strSQL = "select " + sequence_name + ".nextval from DUAL";
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(strSQL);
rs.next();
return rs.getString(1);
Oracle對流水號生成提供了比較好的支持,而且Oracle的生成策略也比SQLServer更高效,消耗更少的資源,資源鎖定情況也比SQLServer少。
(3)
UUID的實現(xiàn)代碼
InetAddress inet = InetAddress .getLocalHost();
Byte[] bytes = inet.getAddress();
String hexInetAddress = hexFormat(getInt(bytes),8);
String thisHashCode=hexFormat(System.identityHashCode(this),8);
MideValue = hexInetAddress+thisHashCode;
Seeder = new SecureRandom();
In node = seeder.nextInt();
Long timeNow = System.currentTimeMillis();
Int timeLow = (int)timeNow&oxFFFFFFF;
Int node = seeder.nextInt();
Return (hexFormat(timeLow,8)+mid+hexFormat(node,8));
UUID是一個基于字符串的主鍵,他有一下字符串組合而成:利用System.currentTimeMillis()精確道毫秒的唯一、IP地址的十六進(jìn)制標(biāo)識、利用System.identityHashCode(this)得到的一個JVM內(nèi)部的唯一地址標(biāo)識和利用隨機(jī)數(shù)生成器生成隨機(jī)數(shù)。
還有很多不同的流水號生成策略,我們不準(zhǔn)備一一羅列。我們的主要問題是要解決在采用不同的序列生成策略時將代碼的修改減到最小。
我們定義的SequenceCreator 類定義了所有流水號生成策略公共的方法,并且把這些方法定義為虛方法,在不同的流水號生成策略代碼中只要覆蓋這些方法即可。序列號生成器工廠類SequenceCreatorFactory的 getSquenceCreator()并不返回具體的流水號生成類,而是返回SequenceCreator,這樣當(dāng)采用不同策略時只要修改getSquenceCreator方法即可。