package org.quickbundle.base.beans.idwrapper; import java.util.Random; import org.quickbundle.base.beans.NumberIncrementService; import org.quickbundle.base.beans.TableIdRuleVo; import org.quickbundle.itf.base.IRmIdWrapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.dao.DataAccessException; /** * 实现集群+高并发下从中心节点获取ID段,并在内存中自增,最小值从1开始 * * @author 白小勇 */ public class NumberIncrementWrapper implements IRmIdWrapper { private static Logger log = LoggerFactory.getLogger(NumberIncrementWrapper.class.getName()); TableIdRuleVo ruleVo = null; NumberIncrementService nfoService = null; static Random random = new Random(); long blocksize = 10000; int maxAttempts = 3; // runtime state long lastId = -2; long nextId = -1; public NumberIncrementWrapper(TableIdRuleVo ruleVo) { this.ruleVo = ruleVo; nfoService = new NumberIncrementService(); } public void init() { //取到本表的最大值,并记录到RM_ID_POOL nextId = nfoService.initIdPool(ruleVo, blocksize); lastId = nextId + blocksize -1; } public String[] nextValue(int length) { String[] result = new String[length]; for (int i = 0; i < length; i++) { result[i] = nextValue(); } return result; } public synchronized String nextValue() { // if no more ids available if (lastId < nextId) { // acquire a next block of ids log.debug("last id " + lastId + " was consumed. acquiring new block..."); // reset the id block lastId = -2; nextId = -1; // try couple of times try { acquireDbidBlock(); } catch (Exception e) { throw new RuntimeException("couldn't acquire block of ids", e); } } return String.valueOf(nextId ++); } protected void acquireDbidBlock() { for (int attempts = maxAttempts; (attempts > 0) && (nextId == -1); attempts--) { try { // acquire block nextId = nfoService.acquireId(ruleVo, blocksize); lastId = nextId + blocksize - 1; log.debug("acquired new id block [" + nextId + "-" + lastId + "]"); } catch (DataAccessException e) { // optimistic locking exception indicating another thread tried to acquire a block of ids concurrently attempts--; // if no attempts left if (attempts == 0) { // fail the surrounding transaction throw new RuntimeException("couldn't acquire block of ids, tried " + maxAttempts + " times"); } // if there are still attempts left, first wait a bit int millis = 20 + random.nextInt(200); log.debug("optimistic locking failure while trying to acquire id block. retrying in " + millis + " millis"); try { Thread.sleep(millis); } catch (InterruptedException e1) { log.debug("waiting after id block locking failure got interrupted"); } } } } }