0

I am so curious about the hibernate optimistic lock (dedicated version way), I checked hibernate source code which tells that it checks version before current transaction commits, but if there is another transaction happens to committed after it query the version column from DB(in a very short time gap), then current transaction considers there is no change, so the old transaction would be replaced wrongly.

EntityVerifyVersionProcess.java

@Override
    public void doBeforeTransactionCompletion(SessionImplementor session) {
        final EntityPersister persister = entry.getPersister();

        if ( !entry.isExistsInDatabase() ) {
            // HHH-9419: We cannot check for a version of an entry we ourselves deleted
            return;
        }

        final Object latestVersion = persister.getCurrentVersion( entry.getId(), session );
        if ( !entry.getVersion().equals( latestVersion ) ) {
            throw new OptimisticLockException(
                    object,
                    "Newer version [" + latestVersion +
                            "] of entity [" + MessageHelper.infoString( entry.getEntityName(), entry.getId() ) +
                            "] found in database"
            );
        }
    }

is such case possible?

Hope there are DB domain experts who would help me on this.

Many thanks.

user2015063
  • 99
  • 1
  • 7
  • That would make it broken and useless. Not a very good advertisement "use optimistic locking, it usually doesn't corrupt your data!". – Kayaman Oct 18 '17 at 05:05
  • hmmm, actually I don't think it is a duplicate question, that question is about optimistic lock mechanism, but I am not... – user2015063 Oct 18 '17 at 06:04
  • You are not what? It seems to be exactly what you're talking about, and no, there's no chance of things breaking. If optimistic locking fails, one transaction will be rolled back. – Kayaman Oct 18 '17 at 06:05
  • hibernate sources code use SQL "SELECT VERSION FROM xx" way to check version change instead of appending "WHERE VERSION=?" clause to do – user2015063 Oct 18 '17 at 06:09

1 Answers1

1

Based on a quick glance of the code, EntityVerifyVersionProcess is used for read transactions, so there's no potential for data loss involved. This would only check that when the transaction commits, it's not returning data that's already stale. With a READ COMMITTED transaction, I suppose this might return data that is instantly going stale, but hard to say without going into details.

Write transactions on the other hand use EntityIncrementVersionProcess, which is a completely different beast and leaves no chance for race conditions.

public void doBeforeTransactionCompletion(SessionImplementor session) {
    final EntityPersister persister = entry.getPersister();
    final Object nextVersion = persister.forceVersionIncrement( entry.getId(), entry.getVersion(), session );
    entry.forceLocked( object, nextVersion );
}
Kayaman
  • 72,141
  • 5
  • 83
  • 121
  • so it(OptimisticLock) uses "SELECT xxx FOR UPDATE " way to lock, instead of locking the record for a long transaction in the beginning, it makes sense, thanks for your help. – user2015063 Oct 19 '17 at 02:21
  • No no. There's no select for update, that would *be* locking the record for the duration of the transaction. It's just that the inner workings are not simple, and the code in the question doesn't handle *updates*, only *selects*. If you're performing updates, then there are other `*Process` classes involved, but I don't know the inner workings so well that I could explain exactly how the flow goes. At some point internally there is the `update foo WHERE version = @oldversion` which fails if the version has been incremented, and avoids any possible race conditions in the db. – Kayaman Oct 19 '17 at 05:29