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 ");
}
binding.getColumnReference().appendColumnForWrite( this, "t" );
appendSql("<=");
appendSql("=");
binding.getValueExpression().accept( this );
}
}

View File

@ -386,21 +386,24 @@ public class OptionalTableUpdateOperation implements SelfExecutingUpdateOperatio
final BindingGroup bindingGroup = jdbcValueBindings.getBindingGroup( tableMapping.getTableName() );
if ( bindingGroup != null ) {
bindingGroup.forEachBinding( (binding) -> {
try {
binding.getValueBinder().bind(
insertStatement,
binding.getValue(),
binding.getPosition(),
session
);
}
catch (SQLException e) {
throw session.getJdbcServices().getSqlExceptionHelper().convert(
e,
"Unable to bind parameter for upsert insert",
jdbcInsert.getSqlString()
);
bindingGroup.forEachBinding( binding -> {
// Skip parameter bindings for e.g. optimistic version check
if ( binding.getPosition() <= jdbcInsert.getParameterBinders().size() ) {
try {
binding.getValueBinder().bind(
insertStatement,
binding.getValue(),
binding.getPosition(),
session
);
}
catch (SQLException e) {
throw session.getJdbcServices().getSqlExceptionHelper().convert(
e,
"Unable to bind parameter for upsert insert",
jdbcInsert.getSqlString()
);
}
}
} );
}

View File

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