多进程多线程,全局唯一的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;