Skip to content

Commit 0d4556b

Browse files
gavinkingmbellade
authored andcommitted
HHH-19522 report failed optimistic lock checking for upsert()
upsert() should throw StaleObjectStateException if the version verification fails
1 parent aefc2d1 commit 0d4556b

File tree

3 files changed

+61
-36
lines changed

3 files changed

+61
-36
lines changed

hibernate-core/src/main/java/org/hibernate/sql/model/jdbc/MergeOperation.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import java.util.List;
1010

11-
import org.hibernate.jdbc.Expectations;
11+
import org.hibernate.jdbc.Expectation;
1212
import org.hibernate.sql.exec.spi.JdbcParameterBinder;
1313
import org.hibernate.sql.model.MutationTarget;
1414
import org.hibernate.sql.model.MutationType;
@@ -25,13 +25,12 @@ public MergeOperation(
2525
MutationTarget<?> mutationTarget,
2626
String sql,
2727
List<? extends JdbcParameterBinder> parameterBinders) {
28-
super( tableDetails, mutationTarget, sql, false, Expectations.NONE, parameterBinders );
28+
super( tableDetails, mutationTarget, sql, false, new Expectation.RowCount(), parameterBinders );
2929
}
3030

3131
@Override
3232
public MutationType getMutationType() {
3333
return MutationType.UPDATE;
3434
}
3535

36-
3736
}

hibernate-core/src/main/java/org/hibernate/sql/model/jdbc/UpsertOperation.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import java.util.List;
1010

11-
import org.hibernate.jdbc.Expectations;
11+
import org.hibernate.jdbc.Expectation;
1212
import org.hibernate.sql.exec.spi.JdbcParameterBinder;
1313
import org.hibernate.sql.model.MutationTarget;
1414
import org.hibernate.sql.model.MutationType;
@@ -25,13 +25,12 @@ public UpsertOperation(
2525
MutationTarget<?> mutationTarget,
2626
String sql,
2727
List<? extends JdbcParameterBinder> parameterBinders) {
28-
super( tableDetails, mutationTarget, sql, false, Expectations.NONE, parameterBinders );
28+
super( tableDetails, mutationTarget, sql, false, new Expectation.RowCount(), parameterBinders );
2929
}
3030

3131
@Override
3232
public MutationType getMutationType() {
3333
return MutationType.UPDATE;
3434
}
3535

36-
3736
}

hibernate-core/src/test/java/org/hibernate/orm/test/stateless/UpsertVersionedTest.java

Lines changed: 57 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,45 +3,72 @@
33
import jakarta.persistence.Entity;
44
import jakarta.persistence.Id;
55
import jakarta.persistence.Version;
6+
import org.hibernate.StaleObjectStateException;
67
import org.hibernate.testing.orm.junit.DomainModel;
78
import org.hibernate.testing.orm.junit.SessionFactory;
89
import org.hibernate.testing.orm.junit.SessionFactoryScope;
910
import org.junit.jupiter.api.Test;
1011

11-
import static org.junit.Assert.assertEquals;
12+
import static org.junit.jupiter.api.Assertions.assertEquals;
13+
import static org.junit.jupiter.api.Assertions.fail;
1214

1315
@SessionFactory
1416
@DomainModel(annotatedClasses = UpsertVersionedTest.Record.class)
1517
public class UpsertVersionedTest {
16-
@Test void test(SessionFactoryScope scope) {
17-
scope.inStatelessTransaction(s-> {
18-
s.upsert(new Record(123L,null,"hello earth"));
19-
s.upsert(new Record(456L,2L,"hello mars"));
20-
});
21-
scope.inStatelessTransaction(s-> {
22-
assertEquals("hello earth",s.get(Record.class,123L).message);
23-
assertEquals("hello mars",s.get(Record.class,456L).message);
24-
});
25-
scope.inStatelessTransaction(s-> {
26-
s.upsert(new Record(123L,0L,"goodbye earth"));
27-
});
28-
scope.inStatelessTransaction(s-> {
29-
assertEquals("goodbye earth",s.get(Record.class,123L).message);
30-
assertEquals("hello mars",s.get(Record.class,456L).message);
31-
});
32-
scope.inStatelessTransaction(s-> {
33-
s.upsert(new Record(456L,3L,"goodbye mars"));
34-
});
35-
scope.inStatelessTransaction(s-> {
36-
assertEquals("goodbye earth",s.get(Record.class,123L).message);
37-
assertEquals("goodbye mars",s.get(Record.class,456L).message);
38-
});
39-
}
40-
@Entity(name = "Record")
41-
static class Record {
42-
@Id Long id;
43-
@Version Long version;
44-
String message;
18+
19+
@Test void test(SessionFactoryScope scope) {
20+
scope.getSessionFactory().getSchemaManager().truncateMappedObjects();
21+
scope.inStatelessTransaction(s-> {
22+
s.upsert(new Record(123L,null,"hello earth"));
23+
s.upsert(new Record(456L,2L,"hello mars"));
24+
});
25+
scope.inStatelessTransaction(s-> {
26+
assertEquals( "hello earth", s.get( Record.class,123L).message );
27+
assertEquals( "hello mars", s.get( Record.class,456L).message );
28+
});
29+
scope.inStatelessTransaction(s-> {
30+
s.upsert(new Record(123L,0L,"goodbye earth"));
31+
});
32+
scope.inStatelessTransaction(s-> {
33+
assertEquals( "goodbye earth", s.get( Record.class,123L).message );
34+
assertEquals( "hello mars", s.get( Record.class,456L).message );
35+
});
36+
scope.inStatelessTransaction(s-> {
37+
s.upsert(new Record(456L,3L,"goodbye mars"));
38+
});
39+
scope.inStatelessTransaction(s-> {
40+
assertEquals( "goodbye earth", s.get( Record.class,123L).message );
41+
assertEquals( "goodbye mars", s.get( Record.class,456L).message );
42+
});
43+
}
44+
45+
@Test void testStaleUpsert(SessionFactoryScope scope) {
46+
scope.getSessionFactory().getSchemaManager().truncateMappedObjects();
47+
scope.inStatelessTransaction( s -> {
48+
s.insert(new Record(789L, 1L, "hello world"));
49+
} );
50+
scope.inStatelessTransaction( s -> {
51+
s.upsert(new Record(789L, 1L, "hello mars"));
52+
} );
53+
try {
54+
scope.inStatelessTransaction( s -> {
55+
s.upsert(new Record( 789L, 1L, "hello venus"));
56+
} );
57+
fail();
58+
}
59+
catch (StaleObjectStateException sose) {
60+
//expected
61+
}
62+
scope.inStatelessTransaction( s-> {
63+
assertEquals( "hello mars", s.get(Record.class,789L).message );
64+
} );
65+
}
66+
67+
@Entity(name = "Record")
68+
static class Record {
69+
@Id Long id;
70+
@Version Long version;
71+
String message;
4572

4673
Record(Long id, Long version, String message) {
4774
this.id = id;

0 commit comments

Comments
 (0)