工厂方法模式
   
以可移植的、可扩展的方式来生成流水号 EJB 应用中的一个难点。 现在比较成熟的流水号生成策略有全局唯一标识(即 UUID )和使用数据库内置流水号生成策略。全局唯一标识有单件模式、根据网络标识( Mac 地址+ IP JVM 唯一对象标识)等策略。不同的数据库也有不同的流水号生成策略:例如 Oracle 采用内置流水号产生机制, SQL Server 则采用 Identity 机制。这给我们带来方便的同时也使得应用程序在不同系统之间移植变得很麻烦。我采用工厂方法模式解决这个问题。
  
结构图
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />
我们首先定义一个基类接口,它定义了各种唯一序列生成器的共同的方法。
abstract public interface SequenceCreator {
  abstract public String getSequenceId(String aId);
  abstract public Integer getSequenceAsInt(String aId);
}
 
两个函数的参数 aId 是不同流水号生成标识。 getSequenceId 是产生以字符串形式返回的流水号, getSequenceAsInt 是以×××形式返回流水号。为了防止无谓的重复,下面的实例中我们将只写各个方法的 getSequenceId 实现。

1 )我们首先看 SQLSequenceCreator 的实现代码

    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());

我们是调用我们自定义的存储过程来生成流水号的 , 存储过程的代码请参看代码。

2 Oracle 的实现代码

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 的实现代码

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 地址的十六进制标识、利用 System.identityHashCode(this) 得到的一个 JVM 内部的唯一地址标识和利用随机数生成器生成随机数。

 

还有很多不同的流水号生成策略,我们不准备一一罗列。我们的主要问题是要解决在采用不同的序列生成策略时将代码的修改减到最小。

我们定义的 SequenceCreator  类定义了所有流水号生成策略公共的方法,并且把这些方法定义为虚方法,在不同的流水号生成策略代码中只要覆盖这些方法即可。序列号生成器工厂类 SequenceCreatorFactory getSquenceCreator() 并不返回具体的流水号生成类,而是返回 SequenceCreator ,这样当采用不同策略时只要修改 getSquenceCreator 方法即可。