{"record":{"id":"202eda521847f549","repo":"hibernate/hibernate-orm","slug":"optimistic-locking-strategies-not-supported-in-sta","errorCode":null,"errorMessage":"Optimistic locking strategies not supported in stateless session","messagePattern":"Optimistic locking strategies not supported in stateless session","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/dialect/lock/LockingStrategy.java","lineNumber":72,"sourceCode":"\t * @param version The current version (or null if not versioned)\n\t * @param object The object logically being locked (currently not used)\n\t * @param timeout timeout in milliseconds, 0 = no wait, -1 = wait indefinitely\n\t * @param session The session from which the lock request originated\n\t *\n\t * @throws StaleObjectStateException Indicates an inability to locate the database row as part of acquiring\n\t * the requested lock.\n\t * @throws LockingStrategyException Indicates a failure in the lock attempt\n\n\t * @deprecated Use {@link #lock(Object, Object, Object, Timeout, SharedSessionContractImplementor)}\n\t */\n\t@Deprecated(since = \"7.1\")\n\tdefault void lock(Object id, Object version, Object object, int timeout, SharedSessionContractImplementor session)\n\t\t\tthrows StaleObjectStateException, LockingStrategyException {\n\t\tif ( session instanceof EventSource eventSource ) {\n\t\t\tlock( id, version, object, timeout, eventSource );\n\t\t}\n\t\telse {\n\t\t\tthrow new UnsupportedOperationException( \"Optimistic locking strategies not supported in stateless session\" );\n\t\t}\n\t}\n\n\tdefault void lock(Object id, Object version, Object object, Timeout timeout, SharedSessionContractImplementor session)\n\t\t\tthrows StaleObjectStateException, LockingStrategyException {\n\t\tlock( id, version, object, timeout.milliseconds(), session );\n\t}\n}\n","sourceCodeStart":54,"sourceCodeEnd":81,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/dialect/lock/LockingStrategy.java#L54-L81","documentation":"LockingStrategy's deprecated default lock(id, version, object, int timeout, session) method only supports regular stateful sessions: it tests whether the session is an EventSource, and otherwise throws UnsupportedOperationException 'Optimistic locking strategies not supported in stateless session'. Optimistic strategies (version verify/increment at commit) rely on the persistence context and action queue that a StatelessSession does not have, hence the hard refusal. The newer Timeout overload delegates to this default method, so it inherits the restriction.","triggerScenarios":"Calling session.lock(...)/buildLockRequest(...) with an optimistic lock mode on a StatelessSession obtained via sessionFactory.openStatelessSession(), where the resolved LockingStrategy falls back to this default method; also direct strategy invocations passing a non-EventSource SharedSessionContractImplementor. Deprecated since 7.1 in favor of the Timeout overload.","commonSituations":"Bulk-processing code using StatelessSession for throughput that later adds session.lock(entity, LockMode.OPTIMISTIC) for consistency; shared service code receiving either session type; migrating batch jobs from Session to StatelessSession without auditing locking calls.","solutions":["Use a regular stateful Session/EntityManager wherever optimistic locking is required","For batch workloads that must stay stateless, switch to explicit pessimistic locks (select for update) or manual version checks via conditional UPDATE","Guard shared code with 'session instanceof EventSource' and choose the locking approach per session type","Audit for LockMode.OPTIMISTIC / OPTIMISTIC_FORCE_INCREMENT usages before introducing StatelessSession"],"exampleFix":"// before\nStatelessSession s = sessionFactory.openStatelessSession();\ns.lock(person, LockMode.OPTIMISTIC);\n\n// after\nSession s = sessionFactory.openSession();\n// optimistic locking works via the action queue on commit\ns.lock(person, LockMode.OPTIMISTIC);","handlingStrategy":"fallback","validationCode":"// Route locking by session type before calling lock\nif (session instanceof org.hibernate.engine.spi.SessionImplementor) {\n    session.lock(person, LockMode.OPTIMISTIC); // stateful: OK\n}\nelse {\n    // StatelessSession: optimistic strategies unsupported - use explicit versioned UPDATE instead\n    int updated = statelessSession.createMutationQuery(\n            \"update Person p set p.version = p.version + 1 where p.id = :id and p.version = :v\")\n            .setParameter(\"id\", id).setParameter(\"v\", version)\n            .executeUpdate();\n    if (updated == 0) throw new OptimisticLockException(person);\n}","typeGuard":null,"tryCatchPattern":"try {\n    session.lock(person, LockMode.OPTIMISTIC);\n}\ncatch (UnsupportedOperationException e) {\n    if (e.getMessage().contains(\"stateless session\")) {\n        throw new IllegalStateException(\"Open a stateful Session for optimistic locking\", e);\n    }\n    throw e;\n}","preventionTips":["Never issue optimistic lock requests through StatelessSession - it has no action queue for version verification","Audit lock calls before migrating batch jobs to StatelessSession","Encapsulate session acquisition so optimistic-locking code paths always receive a stateful Session"],"tags":["hibernate","locking","stateless-session","optimistic-lock"],"backgroundTag":"stateless-session-limitation","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}