package jef.database.meta; import java.sql.SQLException; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicInteger; import javax.persistence.PersistenceException; import jef.common.log.LogUtil; import jef.database.DbCfg; import jef.database.DbClient; import jef.database.DbMetaData; import jef.database.DbUtils; import jef.database.OperateTarget; import jef.database.Sequence; import jef.database.SequenceManager; import jef.tools.JefConfiguration; import jef.tools.StringUtils; /** * Sequence实现的抽象类 * * @author jiyi * */ public abstract class AbstractSequence implements Sequence { private int cacheSize; protected final Queue<Long> cache = new ConcurrentLinkedQueue<Long>(); // 需要初始化 protected String dbKey; protected DbClient session; private final AtomicInteger tryInitCount=new AtomicInteger(); private volatile boolean initSuccess; protected AbstractSequence(OperateTarget target,SequenceManager parent) { cacheSize = JefConfiguration.getInt(DbCfg.SEQUENCE_BATCH_SIZE, 50); if (cacheSize < 1) cacheSize = 1; if (target != null) { this.dbKey = target.getDbkey(); this.session = target.getSession().getNoTransactionSession(); } } protected synchronized void tryInit() { if(!initSuccess){ tryInitCount.incrementAndGet(); try{ initSuccess=doInit(session,dbKey); }catch(SQLException e){ LogUtil.warn("Sequence Implementation creating error.", e); } } } /** * 执行数据库初始化 * @return */ protected abstract boolean doInit(DbClient session,String dbKey) throws SQLException; /** * 将一个已经领出的键值从新塞回到Sequence中 * * @param key */ public void pushBack(long key) { cache.add(key); } public long next() { Long value = cache.poll(); if (value != null){ return value; } try { if(!initSuccess){ if(tryInitCount.get()<3){ tryInit(); if(!initSuccess){ throw new PersistenceException("Sequence/Table ["+this.getName()+"] createing failure."); } }else{ throw new PersistenceException("Sequence/Table ["+this.getName()+"] is not exist, and there will be no attemp to create it."); } } return getFirstAndPushOthers(cacheSize, session, dbKey); } catch (SQLException e) { throw DbUtils.toRuntimeException(e); } } public void clear() { cache.clear(); } /** * * @param size * 要生成的ID数量 * @param conn * @return * @throws SQLException */ protected abstract long getFirstAndPushOthers(int size, DbClient client, String dbKey) throws SQLException; /** * 将从from 到 value的值全部加入缓存(含头含尾) * * @param from * @param value */ protected void pushRange(long from, long value) { for (long i = from; i <= value; i++) { cache.offer(i); } } public int getCacheSize() { return cacheSize; } public void setCacheSize(int cacheSize) { if (cacheSize < 1) cacheSize = 1; this.cacheSize = cacheSize; } protected long caclStartValue(DbMetaData meta, String schema, String table, String column, int initValue, long max) throws SQLException { long start = JefConfiguration.getInt(DbCfg.AUTO_SEQUENCE_OFFSET, -1);// 自动校准 if (start == -1) { long calc = (StringUtils.isNotBlank(table) && StringUtils.isNotBlank(column)) ? meta.getSequenceStartValue(schema, table, column) : initValue; if (calc < max) { start = calc; } } else { start += initValue; } return start; } public boolean checkSequenceValue(String table, String column) throws SQLException { if (StringUtils.isBlank(table) || StringUtils.isBlank(column)) { throw new SQLException(); } long maxInTable = session.getMetaData(dbKey).getSequenceStartValue(null, table, column) - 1; long next = this.next(); pushBack(next); return maxInTable < next; } }