HHH-17949 Fix upsert handling when optimistic locking is involved

This commit is contained in:
Christian Beikov 2024-07-16 16:23:18 +02:00
parent ab3e4e27e0
commit b51acb752d
3 changed files with 22 additions and 28 deletions

View File

@ -215,7 +215,7 @@ public class SqlAstTranslatorWithUpsert<T extends JdbcOperation> extends Abstrac
appendSql(" and "); appendSql(" and ");
} }
binding.getColumnReference().appendColumnForWrite( this, "t" ); binding.getColumnReference().appendColumnForWrite( this, "t" );
appendSql("<="); appendSql("=");
binding.getValueExpression().accept( this ); binding.getValueExpression().accept( this );
} }
} }

View File

@ -386,7 +386,9 @@ public class OptionalTableUpdateOperation implements SelfExecutingUpdateOperatio
final BindingGroup bindingGroup = jdbcValueBindings.getBindingGroup( tableMapping.getTableName() ); final BindingGroup bindingGroup = jdbcValueBindings.getBindingGroup( tableMapping.getTableName() );
if ( bindingGroup != null ) { if ( bindingGroup != null ) {
bindingGroup.forEachBinding( (binding) -> { bindingGroup.forEachBinding( binding -> {
// Skip parameter bindings for e.g. optimistic version check
if ( binding.getPosition() <= jdbcInsert.getParameterBinders().size() ) {
try { try {
binding.getValueBinder().bind( binding.getValueBinder().bind(
insertStatement, insertStatement,
@ -402,6 +404,7 @@ public class OptionalTableUpdateOperation implements SelfExecutingUpdateOperatio
jdbcInsert.getSqlString() jdbcInsert.getSqlString()
); );
} }
}
} ); } );
} }

View File

@ -3,12 +3,7 @@ package org.hibernate.orm.test.stateless;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.Version; import jakarta.persistence.Version;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.OracleDialect;
import org.hibernate.dialect.PostgreSQLDialect;
import org.hibernate.dialect.SQLServerDialect;
import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.RequiresDialect;
import org.hibernate.testing.orm.junit.SessionFactory; import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope; import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -18,10 +13,6 @@ import static org.junit.Assert.assertEquals;
@SessionFactory @SessionFactory
@DomainModel(annotatedClasses = UpsertVersionedTest.Record.class) @DomainModel(annotatedClasses = UpsertVersionedTest.Record.class)
public class UpsertVersionedTest { public class UpsertVersionedTest {
@RequiresDialect(OracleDialect.class)
@RequiresDialect(H2Dialect.class)
@RequiresDialect(SQLServerDialect.class)
@RequiresDialect(value = PostgreSQLDialect.class, matchSubTypes = false)
@Test void test(SessionFactoryScope scope) { @Test void test(SessionFactoryScope scope) {
scope.inStatelessTransaction(s-> { scope.inStatelessTransaction(s-> {
s.upsert(new Record(123L,null,"hello earth")); s.upsert(new Record(123L,null,"hello earth"));
@ -32,21 +23,21 @@ public class UpsertVersionedTest {
assertEquals("hello mars",s.get(Record.class,456L).message); assertEquals("hello mars",s.get(Record.class,456L).message);
}); });
scope.inStatelessTransaction(s-> { scope.inStatelessTransaction(s-> {
s.upsert(new Record(123L,1L,"goodbye earth")); s.upsert(new Record(123L,0L,"goodbye earth"));
}); });
scope.inStatelessTransaction(s-> { scope.inStatelessTransaction(s-> {
assertEquals("goodbye earth",s.get(Record.class,123L).message); assertEquals("goodbye earth",s.get(Record.class,123L).message);
assertEquals("hello mars",s.get(Record.class,456L).message); assertEquals("hello mars",s.get(Record.class,456L).message);
}); });
scope.inStatelessTransaction(s-> { scope.inStatelessTransaction(s-> {
s.upsert(new Record(456L,4L,"goodbye mars")); s.upsert(new Record(456L,3L,"goodbye mars"));
}); });
scope.inStatelessTransaction(s-> { scope.inStatelessTransaction(s-> {
assertEquals("goodbye earth",s.get(Record.class,123L).message); assertEquals("goodbye earth",s.get(Record.class,123L).message);
assertEquals("goodbye mars",s.get(Record.class,456L).message); assertEquals("goodbye mars",s.get(Record.class,456L).message);
}); });
} }
@Entity @Entity(name = "Record")
static class Record { static class Record {
@Id Long id; @Id Long id;
@Version Long version; @Version Long version;