简体   繁体   中英

How to safely convert Hibernate hi/lo to pooled?

Unfortunately, I started a project with

@Id
@Generated(GenerationTime.INSERT)
@GeneratedValue(generator = "hibernate_sequence")
@GenericGenerator(
        name = "hibernate_sequence",
        strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
        parameters = {
                @Parameter(name = "increment_size", value = "100"),
                @Parameter(name = "optimizer", value = "hilo")
        })
private Integer id;

before I learnt that there are better ways. The problem is that my hi/lo algorithm generates values which have to be multiplied by 100 before they get used. So while I see a sequence value like 1107 in the database, it means something like that values 110700 to 110799 will get used for the next ID. This makes adding entities manually pretty error-prone.

So I'd like to switch the algorithm to pooled or pooled-lo. For this I need to change the stored value to maybe 110800? Losing a few ID's obviously doesn't matter, but I'm asking as I need a fool-proof way.

A side question (admittedly, opinion-based): Should I go for pooled or pooled-io?

Basing on the code of the HiLoOptimizer.generate

@Override
public synchronized Serializable generate(AccessCallback callback) {
    final GenerationState generationState = locateGenerationState( callback.getTenantIdentifier() );

    if ( generationState.lastSourceValue == null ) {
        // first call, so initialize ourselves.  we need to read the database
        // value and set up the 'bucket' boundaries
        generationState.lastSourceValue = callback.getNextValue();
        while ( generationState.lastSourceValue.lt( 1 ) ) {
            generationState.lastSourceValue = callback.getNextValue();
        }
        // upperLimit defines the upper end of the bucket values
        generationState.upperLimit = generationState.lastSourceValue.copy().multiplyBy( incrementSize ).increment();
        // initialize value to the low end of the bucket
        generationState.value = generationState.upperLimit.copy().subtract( incrementSize );
    }
    else if ( ! generationState.upperLimit.gt( generationState.value ) ) {
        generationState.lastSourceValue = callback.getNextValue();
        generationState.upperLimit = generationState.lastSourceValue.copy().multiplyBy( incrementSize ).increment();
    }
    return generationState.value.makeValueThenIncrement();
}

on the very first run:

  1. Current value from the DB is read ( lastSourceValue ). Note that callback is expected to update DB state automatically. For SequenceStyleGenerator this should be done by the DB-specific implementation of the sequence-like feature.

  2. Code enusres that lastSourceValue >= 1

  3. upperLimit = incrementSize * lastSourceValue + 1

  4. value = upperLimit - incrementSize = incrementSize * ( lastSourceValue - 1) + 1. Code ensures that lastSourceValue >= 1 so that ( lastSourceValue - 1) is still not negative and the value is at least 1

  5. the value is returned as the first generated ID

So if the sequence in your DB stores 1234, then the first ID that is guaranteed to be unused yet (ie even not pre-pooled) is 123 3 01 = (1234 - 1) * 100 + 1.

Pessimistic mode : still all the maths and logic aside why not add 2 * increment_size more just to be on the very safe side?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM