现在的位置: 首页 > 综合 > 正文

IdGenerator

2016年05月18日 ⁄ 综合 ⁄ 共 2134字 ⁄ 字号 评论关闭

多进程多线程,全局唯一的id自增


public class IdGenerator {
	private final static String SELECT_ALL_ID_INFO = "SELECT Name FROM IDGenInfo";
	private final static String SELECT_ID_INFO = "SELECT Current, Step FROM IDGenInfo WHERE Name = ? FOR UPDATE";
	private final static String UPDATE_ID_INFO = "UPDATE IDGenInfo SET Current = Current + Step WHERE Name = ?";

	private ConcurrentHashMap<String, IdInfo> counters = new ConcurrentHashMap<String, IdInfo>();
	private boolean enabled = true;

	private IdGenerator() {
		ArrayList<String> names = DbManager.instance().executeQuery_ObjectList(
				SELECT_ALL_ID_INFO, ScalarResultBuilder.stringResultBuilder);
		for (String name : names) {
			counters.put(name, new IdInfo(name, 0, 0));
		}
	}

	private final static IdGenerator _instance = new IdGenerator();

	public static IdGenerator instance() {
		return _instance;
	}
	
	private long genNewId(String name) {
		if (!enabled){
			ApplicationLocal.instance().error("invalid operation:can Not gen new id after persist!");
			return -1;
		}
		
		IdInfo ii = counters.get(name);
		if (ii == null) {
			return -1;
		}

		synchronized (ii) {
			if (ii.count == 0) {
				fillIdInfo(ii, name);
				if (ii.count == 0) {
					return -1;
				}
			}
			ii.count--;
			ii.val++;
			return ii.val;
		}
	}
	
	public int next(String name) {
		return (int)genNewId(name);
	}
	
	public long nextBigId(String name){
		return genNewId(name);
	}

	private void fillIdInfo(IdInfo ii, String name) {
		Connection conn = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		try {
			conn = DbManager.instance().getConnection();
			conn.setAutoCommit(false);

			stmt = conn.prepareStatement(SELECT_ID_INFO);
			stmt.setString(1, name);
			rs = stmt.executeQuery();
			rs.next();

			ii.val = rs.getLong("Current");
			ii.count = rs.getInt("Step");

			stmt.close();

			stmt = conn.prepareStatement(UPDATE_ID_INFO);
			stmt.setString(1, name);
			stmt.execute();

			conn.commit();
		} catch (Exception ex) {
			try {
				conn.rollback();
			} catch (Exception e) {

			}

			ii.reset();
			ApplicationLocal.instance().error("fill id info error :", ex);
		} finally {
			DbManager.releaseDbResource(rs, stmt, conn);
		}
	}	

	static class IdInfo {
		public String name;
		public long val;
		public int count;

		public IdInfo(String name, long val, int count) {
			this.name = name;
			this.val = val;
			this.count = count;
		}

		public void reset() {
			this.val = -1;
			this.count = 0;
		}
	}
}

表结构:

CREATE TABLE `IDGenInfo` (
`Name` VARCHAR(45) NOT NULL,
`Current` BIGINT(10) UNSIGNED NOT NULL,
`Step` MEDIUMINT(8) UNSIGNED NOT NULL,
PRIMARY KEY (`Name`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB;

抱歉!评论已关闭.