hibernate/hibernate-orm · error · UnsupportedOperationException

Follow-on collection-table locking with composite keys is no

Error message

Follow-on collection-table locking with composite keys is not supported for Dialects which do not support tuples (row constructor syntax) as part of an in-list

What it means

When a collection with a composite key must be locked in the collection table via follow-on locking, LockingHelper builds an IN-list of tuple row constructors ((k1,k2) IN ((?,?),(?,?))). That syntax is only emitted when Dialect.supportsRowValueConstructorSyntaxInInList() returns true; otherwise applyCompositeCollectionKeyTableLockRestrictions (the ownerDetailsMap overload) throws UnsupportedOperationException - a known platform limitation, marked 'for now' in the source.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/sql/exec/internal/lock/LockingHelper.java:268

						restriction.addExpression( jdbcParameter );
						parameterBindings.addBinding( jdbcParameter,
								new JdbcParameterBindingImpl( jdbcMapping, value ) );
					},
					session
			);
		} );
	}

	private static InListPredicate applyCompositeCollectionKeyTableLockRestrictions(
			PluralAttributeMapping attributeMapping,
			ForeignKeyDescriptor keyDescriptor,
			TableReference tableReference,
			JdbcParameterBindingsImpl parameterBindings,
			Map<Object, EntityDetails> ownerDetailsMap,
			SharedSessionContractImplementor session) {
		if ( !session.getDialect().supportsRowValueConstructorSyntaxInInList() ) {
			// for now...
			throw new UnsupportedOperationException(
					"Follow-on collection-table locking with composite keys is not supported for Dialects"
					+ " which do not support tuples (row constructor syntax) as part of an in-list"
			);
		}

		final int jdbcTypeCount = keyDescriptor.getJdbcTypeCount();
		final List<ColumnReference> columnReferences = new ArrayList<>( jdbcTypeCount );
		keyDescriptor.forEachSelectable( (selectionIndex, selectableMapping) -> {
			columnReferences.add( new ColumnReference( tableReference, selectableMapping ) );
		} );
		final InListPredicate inListPredicate = new InListPredicate( new SqlTuple( columnReferences, keyDescriptor ) );

		ownerDetailsMap.forEach( (o, entityDetails) -> {
			final var collectionInstance =
					(PersistentCollection<?>)
							entityDetails.entry().getLoadedState()[attributeMapping.getStateArrayPosition()];
			final Object collectionKeyValue = collectionInstance.getKey();

View on GitHub (pinned to fad1729dce)

Solutions

  1. Lock the owner row instead of the collection, avoiding follow-on collection-table locking
  2. Rewrite the lock as explicit SQL with AND-ed per-column predicates via a native query
  3. Use a dialect whose database supports row-value constructors in IN-lists (Oracle, DB2, PostgreSQL), or override supportsRowValueConstructorSyntaxInInList() if your database actually supports it
  4. Remap the collection with a single-column key (collection id / surrogate join-table key) instead of a composite FK

Example fix

-- before (Hibernate-issued tuple IN, unsupported on this dialect)
-- where (k1, k2) in ((?, ?), (?, ?)) for update

-- after (native locking query, dialect-safe)
select id from CollectionTable where ownerId = :id and ownerKey2 = :k2 for update
Defensive patterns

Strategy: fallback

Validate before calling

boolean tupleInListSupported(SharedSessionContractImplementor session) {
    return session.getDialect().supportsRowValueConstructorSyntaxInInList();
}

Prevention

When it happens

Trigger: Pessimistic locking of a collection whose owner FK is composite (owner entity uses @EmbeddedId/@IdClass) - e.g. session.buildLockRequest(...).lock() on an initialized collection or a query with LockMode.PESSIMISTIC_WRITE fetching it - on a dialect where supportsRowValueConstructorSyntaxInInList() is false (SQL Server, MySQL).

Common situations: Entities with composite identifiers migrated to databases whose dialect lacks tuple IN-list support; softwares relying on collection-table locking with composite FKs; tests passing on PostgreSQL/DB2 but failing on SQL Server/MySQL.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/f200b12ac1c263f0. Report an issue: GitHub.