易学设计模式十 单例序列键生成器
数据库有很多种,例如Oracle,DB2,Sybase,MySql,SQL Server等等,他们有的提供主键生成,有的不提供,提供的方式也不一样,如果有的系统需要同时支持多种数据库,就要求主键生成更有通用性,下面就给出解决方案。
使用表存储,表有两个列,一个存放键名,一个存放键值
取值时先更新数据库键值+20;然后查询出增加后的值,例如我们更新后的值是1000,每次增加20,现在可用的key = 1000 -20 +1 = 981;这样做的好处就是缓存主键,不用增加一个就修改,查询一次数据库,我们增加20次才查询一次数据库。
public class KeyGenerator {private static Map keygens = new HashMap(10);private static final int POOL_SIZE = 20;private KeyInfo keyinfo;private KeyGenerator(){}private KeyGenerator(String keyName) {keyinfo = new KeyInfo(POOL_SIZE, keyName);}public static synchronized KeyGenerator getInstance(String keyName) {KeyGenerator keygen;if(keygens.containsKey(keyName)) {keygen = (KeyGenerator)keygens.get(keyName);} else {keygen = new KeyGenerator(keyName);keygens.put(keyName, keygen);}return keygen;}public synchronized int getNextKey() {return keyinfo.getnextKey();}}public class KeyInfo {private int keyMax;private int keyMin;private int nextKey;private int poolSize;private String keyName;public KeyInfo(int poolSize, String keyName) {this.poolSize = poolSize;this.keyName = keyName;retrieveFromDB();}public int getKeyMax() {return keyMax;}public int getKeyMin() {return keyMin;}public int getnextKey() {if(nextKey > keyMax) {retrieveFromDB();}return nextKey++;}private void retrieveFromDB() {String updateSql = "UPDATE KEYTABLE SET KEYVALUE = KEYVALUE + "+ poolSize + "where keyname = '" + keyName +"'";String selectSql = "select keyvalue from keytable where keyname = '"+ keyName +"'";//execute the above queries in a transaction and commit it//assume the value returned is 1000int keyFromDB = 1000;keyMax = keyFromDB;keyMin = keyFromDB - poolSize + 1;nextKey = keyMin;}}public class Client {public static void main(String[] args) {KeyGenerator keygen = KeyGenerator.getInstance("PO_NUMBER");for(int i=0; i < 20; i++) {System.out.println("key(" + (i+1)+")=" +keygen.getNextKey());}}}