AllocatableIdGenerator.java
package com.github.mygreen.sqlmapper.core.id;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* 挿入前に予めIDを生成を行うID生成を行う抽象クラスです。
* <p>大量にレコードを導入するときは効率的に処理を行うことができます。
* <p>ただし、予めIDを生成してキャッシュしておくため、プロセスを再起動すると生成済みのキャッシュされたIDは使われず欠番となります。
*
* @version 0.3
* @author T.TSUCHIE
*
*/
@RequiredArgsConstructor
public abstract class AllocatableIdGenerator {
/**
* 割り当てサイズ
*/
@Getter
protected final long allocationSize;
/**
* 割り当てているIDのキャッシュ。
*/
protected Map<String, AllocatedIdContext> allocatedIdCache = new ConcurrentHashMap<>();
/**
* 現在のカウンターの値を取得する。
* @param key 取得するシーケンス名
* @return 現在のカウンターの値
*/
protected abstract long getCurrentValue(String key);
/**
* 新たに値を割り当てる。
* @param key 割り当てるキーの名称
* @param allocationSize 割り当てる値
* @return 割り当て後のカウンターの値
*/
protected abstract long allocateValue(String key, long allocationSize);
/**
* 新しいIDを取得します。
* @param key シーケンス名
* @return 新たらしいID
*/
public long nextValue(final String key) {
return allocatedIdCache.computeIfAbsent(key, k -> new AllocatedIdContext(key)).getNextValue();
}
/**
* IDのキャッシュ情報をクリアします。
* <p>クリアすることで、次回、{@link #nextValue(String)}を呼び出した時に、最新のDBの情報を反映した状態になります。
*
* @since 0.3
* @param key 割り当てるキーの名称
*/
protected void clear(final String key) {
allocatedIdCache.remove(key);
}
/**
* 割り当てられたIDの情報を保持する。
*
*
* @author T.TSUCHIE
*
*/
@RequiredArgsConstructor
public class AllocatedIdContext {
/**
* 生成用のキー
*/
private final String key;
/**
* 現在値
*/
private long currentValue = -1l;
/**
* 割り当て済みの個数
*/
private long allocated = -1L;
/**
* 新しいIDを払い出します。
* <p>未割当のキャッシュしているIDがあれば、そちらを払い出します。
*
* @return 新しいIDを返します。
*/
public synchronized long getNextValue() {
if(currentValue < 0l) {
// 現在の値の読み込み
this.currentValue = getCurrentValue(key);
}
if(allocated < 0l || allocated >= allocationSize) {
// 未割当の場合 or 割り当てた個数が確保数を超える場合
// キャッシュサイズ分を確保し、割り当て数をリセット
this.allocated = 1l;
this.currentValue = allocateValue(key, allocationSize) - allocationSize;
} else {
// 割り当てた個数が確保数未満の場合、割り当て数を+1
this.allocated++;
this.currentValue++;
}
return currentValue;
}
}
}