2010年6月19日星期六

2010/6/20 一种 Database+程序 的ID生成策略

特点:持久化、通用性、性能好、多进程共用。
这种实现保证了id递增的唯一性,并且多个VM同时使用同一个Database也没问题,vm突然强制关闭也没问题。

方法概述:采用 Database+VM(表示一个程序)结合的策略生成ID,生成的ID为递增的整数。用Database做id生成的持久层,采用vm进行分段递增。由程序负责一个段内的递增,vm每次开始分配id前先向数据库申请一段可用id。数据库记录上次分配出去的id最大值。

具体方法:数据库中建一张表,表中有一个长整数的Id字段,负责记录已分配出的ID最大值。然后程序在开始生成id前,先向数据库申请一段id,获得这段id的起始值和最大值,然后程序自己就可以在这段范围内采用原子递增方式分配id了。id段用完了就再次向数据库申请。申请的id段的大小由程序自己指定,大小适中即可。

申请的过程就是get and set,这个过程要保证数据一致。不一定采用事物的方式来保证,因为每个程序可以分配一段,所以冲突的可能性小,属于乐观的情况,所以可以采用非事物的方式如果不一致重试几次即可。

所谓ID,即唯一标识符,所以ID生成器的实现目标就是要保证每次分配的id唯一。
既然id生成过程是在程序中完成的,如果程序退出或强制关闭了,那么下次程序启动时会再次向数据库申请新的id段,因而id唯一性是有保证的,但不保证id一定是连续的,程序退出时可能会浪费掉少量段内还没分配完的id。

特点:
  1. 持久化:使用数据库记录上次分配出的最大id。一般而言,如果仅使用程序自身生成id,只能保证程序一次性运行中生成的id可靠,下次再运行就不成了。除了UUID等特殊算法外,一般ID生成策略是需要持久化一些数据的,而持久化的方法无疑最好是使用数据库。
  2. 通用性:只是自己在数据库新建一个简单的表,其它工作都有程序完成,因而不依赖于特定数据库的主键或Sequence生成方式,具有很好的可移植性。(不依赖于特定数据库带来的好处是可移植性,坏处就是这部分工作转给了程序自己实现)
  3. 性能好:因为不是每生成一个id都要更新数据库,而是在程序中完成的,所以效率高,性能好。
  4. 多进程共用:多个程序同时使用一张数据表也没问题,只要保证vm向数据库申请id段的一致性即可,由数据库做中介。

上面描述的方法只是利用了数据库表中的一条记录维护一个递增的ID,可以使用多条记录维护多种不相关的ID,供系统中的多处使用。

这个实现方法是在 Openfire 中使用的 ID 生成方法,具体实现见org.jivesoftware.database.SequenceManager。
表结构:
CREATE TABLE ofID (
  idType                INTEGER         NOT NULL,
  id                    BIGINT          NOT NULL,
  PRIMARY KEY (idType)
);

182 条评论: