Skip to content

Commit 39e8da9

Browse files
gavinkingmbellade
authored andcommitted
HHH-19482 fix handling of lock modes for reads outside tx
and clean up some error messages (cherry picked from commit 3189f0e)
1 parent 6076711 commit 39e8da9

18 files changed

+106
-100
lines changed

hibernate-core/src/main/java/org/hibernate/LockMode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public enum LockMode implements FindOption, RefreshOption {
5252
* rather than pull it from a cache.
5353
* <p>
5454
* This is the "default" lock mode, the mode requested by calling
55-
* {@link Session#get(Class, Object)} without passing an explicit
55+
* {@link Session#find(Class, Object)} without passing an explicit
5656
* mode. It permits the state of an object to be retrieved from
5757
* the cache without the cost of database access.
5858
*

hibernate-core/src/main/java/org/hibernate/Session.java

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -825,19 +825,32 @@ public interface Session extends SharedSessionContract, EntityManager {
825825
void remove(Object object);
826826

827827
/**
828-
* Determine the current {@link LockMode} of the given managed instance associated
829-
* with this session.
828+
* Determine the current {@linkplain LockMode lock mode} held on the given
829+
* managed instance associated with this session.
830+
* <p>
831+
* Unlike the JPA-standard {@link #getLockMode}, this operation may be
832+
* called when no transaction is active, in which case it should return
833+
* {@link LockMode#NONE}, indicating that no pessimistic lock is held on
834+
* the given entity.
830835
*
831836
* @param object a persistent instance associated with this session
832837
*
833-
* @return the current lock mode
838+
* @return the lock mode currently held on the given entity
839+
*
840+
* @throws IllegalStateException if the given instance is not associated
841+
* with this persistence context
842+
* @throws ObjectDeletedException if the given instance was already
843+
* {@linkplain #remove removed}
834844
*/
835845
LockMode getCurrentLockMode(Object object);
836846

837847
/**
838-
* Completely clear the session. Evict all loaded instances and cancel all pending
839-
* saves, updates and deletions. Do not close open iterators or instances of
840-
* {@link ScrollableResults}.
848+
* Completely clear the persistence context. Evict all loaded instances,
849+
* causing every managed entity currently associated with this session to
850+
* transition to the detached state, and cancel all pending insertions,
851+
* updates, and deletions.
852+
* <p>
853+
* Does not close open iterators or instances of {@link ScrollableResults}.
841854
*/
842855
@Override
843856
void clear();

hibernate-core/src/main/java/org/hibernate/engine/internal/ImmutableEntityEntry.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,10 @@ public static EntityEntry deserialize(
113113
(String) ois.readObject(),
114114
ois.readObject(),
115115
Status.valueOf( (String) ois.readObject() ),
116-
( previousStatusString = (String) ois.readObject() ).length() == 0
117-
? null
118-
: Status.valueOf( previousStatusString ),
116+
( previousStatusString = (String) ois.readObject() )
117+
.isEmpty()
118+
? null
119+
: Status.valueOf( previousStatusString ),
119120
(Object[]) ois.readObject(),
120121
(Object[]) ois.readObject(),
121122
ois.readObject(),

hibernate-core/src/main/java/org/hibernate/engine/internal/ImmutableEntityEntryFactory.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
*
1919
* @author Emmanuel Bernard
2020
*/
21-
public class ImmutableEntityEntryFactory implements EntityEntryFactory {
21+
@Deprecated(since = "7", forRemoval = true)
22+
public final class ImmutableEntityEntryFactory implements EntityEntryFactory {
2223
/**
2324
* Singleton access
2425
*/

hibernate-core/src/main/java/org/hibernate/engine/internal/MutableEntityEntry.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,10 @@ public static EntityEntry deserialize(
8383
(String) ois.readObject(),
8484
ois.readObject(),
8585
Status.valueOf( (String) ois.readObject() ),
86-
( previousStatusString = (String) ois.readObject() ).length() == 0
87-
? null
88-
: Status.valueOf( previousStatusString ),
86+
( previousStatusString = (String) ois.readObject() )
87+
.isEmpty()
88+
? null
89+
: Status.valueOf( previousStatusString ),
8990
(Object[]) ois.readObject(),
9091
(Object[]) ois.readObject(),
9192
ois.readObject(),

hibernate-core/src/main/java/org/hibernate/engine/internal/MutableEntityEntryFactory.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
*
1919
* @author Emmanuel Bernard
2020
*/
21-
public class MutableEntityEntryFactory implements EntityEntryFactory {
21+
@Deprecated(since = "7", forRemoval = true)
22+
public final class MutableEntityEntryFactory implements EntityEntryFactory {
2223
/**
2324
* Singleton access
2425
*/

hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java

Lines changed: 27 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -654,58 +654,34 @@ public EntityEntry addEntry(
654654
final EntityPersister persister,
655655
final boolean disableVersionIncrement) {
656656
assert lockMode != null;
657-
658-
final EntityEntry e;
659-
660-
/*
661-
IMPORTANT!!!
662-
663-
The following instanceof checks and castings are intentional.
664-
665-
DO NOT REFACTOR to make calls through the EntityEntryFactory interface, which would result
666-
in polymorphic call sites which will severely impact performance.
667-
668-
When a virtual method is called via an interface the JVM needs to resolve which concrete
669-
implementation to call. This takes CPU cycles and is a performance penalty. It also prevents method
670-
inlining which further degrades performance. Casting to an implementation and making a direct method call
671-
removes the virtual call, and allows the methods to be inlined. In this critical code path, it has a very
672-
large impact on performance to make virtual method calls.
673-
*/
674-
if ( persister.getEntityEntryFactory() instanceof MutableEntityEntryFactory ) {
675-
//noinspection RedundantCast
676-
e = ( (MutableEntityEntryFactory) persister.getEntityEntryFactory() ).createEntityEntry(
677-
status,
678-
loadedState,
679-
rowId,
680-
id,
681-
version,
682-
lockMode,
683-
existsInDatabase,
684-
persister,
685-
disableVersionIncrement,
686-
this
687-
);
688-
}
689-
else {
690-
//noinspection RedundantCast
691-
e = ( (ImmutableEntityEntryFactory) persister.getEntityEntryFactory() ).createEntityEntry(
692-
status,
693-
loadedState,
694-
rowId,
695-
id,
696-
version,
697-
lockMode,
698-
existsInDatabase,
699-
persister,
700-
disableVersionIncrement,
701-
this
702-
);
703-
}
704-
705-
entityEntryContext.addEntityEntry( entity, e );
706-
657+
final EntityEntry entityEntry =
658+
persister.isMutable()
659+
? new MutableEntityEntry(
660+
status,
661+
loadedState,
662+
rowId,
663+
id,
664+
version,
665+
lockMode,
666+
existsInDatabase,
667+
persister,
668+
disableVersionIncrement,
669+
this
670+
)
671+
: new ImmutableEntityEntry(
672+
status,
673+
loadedState,
674+
rowId,
675+
id,
676+
version,
677+
lockMode,
678+
existsInDatabase,
679+
persister,
680+
disableVersionIncrement
681+
);
682+
entityEntryContext.addEntityEntry( entity, entityEntry );
707683
setHasNonReadOnlyEnties( status );
708-
return e;
684+
return entityEntry;
709685
}
710686

711687
@Override
@@ -715,7 +691,6 @@ public EntityEntry addReferenceEntry(
715691
final EntityEntry entityEntry = asManagedEntity( entity ).$$_hibernate_getEntityEntry();
716692
entityEntry.setStatus( status );
717693
entityEntryContext.addEntityEntry( entity, entityEntry );
718-
719694
setHasNonReadOnlyEnties( status );
720695
return entityEntry;
721696
}

hibernate-core/src/main/java/org/hibernate/engine/spi/EntityEntryFactory.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313
* Contract to build {@link EntityEntry}
1414
*
1515
* @author Emmanuel Bernard
16+
*
17+
* @deprecated No longer used
1618
*/
19+
@Deprecated(since = "7", forRemoval = true)
1720
public interface EntityEntryFactory extends Serializable {
1821

1922
/**

hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -525,9 +525,7 @@ private void checksBeforeQueryCreation() {
525525
public void prepareForQueryExecution(boolean requiresTxn) {
526526
checksBeforeQueryCreation();
527527
if ( requiresTxn && !isTransactionInProgress() ) {
528-
throw new TransactionRequiredException(
529-
"Query requires transaction be in progress, but no transaction is known to be in progress"
530-
);
528+
throw new TransactionRequiredException( "No active transaction" );
531529
}
532530
}
533531

hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -554,13 +554,13 @@ public LockMode getCurrentLockMode(Object object) {
554554
if ( e == null ) {
555555
throw new IllegalArgumentException( "Given entity is not associated with the persistence context" );
556556
}
557-
558-
if ( e.getStatus().isDeletedOrGone() ) {
559-
throw new ObjectDeletedException( "The given object was deleted", e.getId(),
557+
else if ( e.getStatus().isDeletedOrGone() ) {
558+
throw new ObjectDeletedException( "Given entity was removed", e.getId(),
560559
e.getPersister().getEntityName() );
561560
}
562-
563-
return e.getLockMode();
561+
else {
562+
return e.getLockMode();
563+
}
564564
}
565565

566566
@Override
@@ -2611,7 +2611,7 @@ private static CacheStoreMode determineCacheStoreMode(Map<String, Object> settin
26112611
}
26122612

26132613
private void checkTransactionNeededForUpdateOperation() {
2614-
checkTransactionNeededForUpdateOperation( "no transaction is in progress" );
2614+
checkTransactionNeededForUpdateOperation( "No active transaction" );
26152615
}
26162616

26172617
@Override
@@ -2772,11 +2772,11 @@ public LockModeType getLockMode(Object entity) {
27722772
checkOpen();
27732773

27742774
if ( !isTransactionInProgress() ) {
2775-
throw new TransactionRequiredException( "Call to EntityManager#getLockMode should occur within transaction according to spec" );
2775+
throw new TransactionRequiredException( "No active transaction" );
27762776
}
27772777

27782778
if ( !contains( entity ) ) {
2779-
throw getExceptionConverter().convert( new IllegalArgumentException( "entity not in the persistence context" ) );
2779+
throw getExceptionConverter().convert( new IllegalArgumentException( "Entity not associated with the persistence context" ) );
27802780
}
27812781

27822782
return LockModeTypeHelper.getLockModeType( getCurrentLockMode( entity ) );

0 commit comments

Comments
 (0)