Skip to content

Commit 0cb093d

Browse files
author
Tigran Sargsyan
committed
follow-on-locking problem
1 parent 0cb8332 commit 0cb093d

File tree

4 files changed

+146
-26
lines changed

4 files changed

+146
-26
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,114 @@
11
package org.hibernate.bugs;
22

3-
import org.junit.jupiter.api.AfterEach;
4-
import org.junit.jupiter.api.BeforeEach;
5-
import org.junit.jupiter.api.Test;
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
64

75
import jakarta.persistence.EntityManager;
86
import jakarta.persistence.EntityManagerFactory;
7+
import jakarta.persistence.LockModeType;
98
import jakarta.persistence.Persistence;
9+
import jakarta.persistence.TypedQuery;
10+
import java.util.List;
11+
import java.util.concurrent.BrokenBarrierException;
12+
import java.util.concurrent.CyclicBarrier;
13+
import org.hibernate.bugs.entity.MainEntity;
14+
import org.hibernate.bugs.entity.RelatedEntity;
15+
import org.junit.jupiter.api.AfterEach;
16+
import org.junit.jupiter.api.BeforeEach;
17+
import org.junit.jupiter.api.Test;
1018

1119
/**
1220
* This template demonstrates how to develop a test case for Hibernate ORM, using the Java Persistence API.
1321
*/
1422
class JPAUnitTestCase {
1523

16-
private EntityManagerFactory entityManagerFactory;
17-
18-
@BeforeEach
19-
void init() {
20-
entityManagerFactory = Persistence.createEntityManagerFactory( "templatePU" );
21-
}
22-
23-
@AfterEach
24-
void destroy() {
25-
entityManagerFactory.close();
26-
}
27-
28-
// Entities are auto-discovered, so just add them anywhere on class-path
29-
// Add your tests, using standard JUnit.
30-
@Test
31-
void hhh123Test() throws Exception {
32-
EntityManager entityManager = entityManagerFactory.createEntityManager();
33-
entityManager.getTransaction().begin();
34-
// Do stuff...
35-
entityManager.getTransaction().commit();
36-
entityManager.close();
37-
}
24+
private EntityManagerFactory entityManagerFactory;
25+
26+
@BeforeEach
27+
void init() {
28+
entityManagerFactory = Persistence.createEntityManagerFactory("templatePU");
29+
}
30+
31+
@AfterEach
32+
void destroy() {
33+
entityManagerFactory.close();
34+
}
35+
36+
@Test
37+
void hhh123Test() throws Exception {
38+
39+
long id = fillData();
40+
41+
var threadsCount = 50;
42+
CyclicBarrier cyclicBarrier = new CyclicBarrier(threadsCount);
43+
44+
Thread[] threads = new Thread[threadsCount];
45+
for (var i = 0; i < threadsCount; i++) {
46+
var thread = new Thread(() -> {
47+
EntityManager entityManager = entityManagerFactory.createEntityManager();
48+
var transaction = entityManager.getTransaction();
49+
50+
try {
51+
cyclicBarrier.await();
52+
} catch (InterruptedException | BrokenBarrierException e) {
53+
throw new RuntimeException(e);
54+
}
55+
56+
transaction.begin();
57+
58+
TypedQuery<MainEntity> query = entityManager.createQuery(
59+
"SELECT m FROM MainEntity m INNER JOIN m.relatedEntity WHERE m.id = :id",
60+
MainEntity.class
61+
);
62+
query.setParameter("id", id);
63+
// test passes, if followOnLocking is disabled
64+
query.setHint("hibernate.query.followOnLocking", true);
65+
query.setLockMode(LockModeType.PESSIMISTIC_WRITE);
66+
var result = query.getSingleResult();
67+
68+
result.mainCounter++;
69+
result.relatedEntity.get(0).relatedCounter++;
70+
entityManager.merge(result);
71+
entityManager.flush();
72+
73+
transaction.commit();
74+
entityManager.close();
75+
});
76+
77+
thread.start();
78+
threads[i] = thread;
79+
}
80+
81+
for (var thread : threads) {
82+
thread.join();
83+
}
84+
85+
EntityManager entityManager = entityManagerFactory.createEntityManager();
86+
var transaction = entityManager.getTransaction();
87+
transaction.begin();
88+
var entity = entityManager.find(MainEntity.class, id);
89+
assertEquals(threadsCount, entity.mainCounter);
90+
assertEquals(threadsCount, entity.relatedEntity.get(0).relatedCounter);
91+
entityManager.getTransaction().commit();
92+
entityManager.close();
93+
}
94+
95+
private long fillData() {
96+
var entityManager = entityManagerFactory.createEntityManager();
97+
var transaction = entityManager.getTransaction();
98+
transaction.begin();
99+
MainEntity mainEntity = new MainEntity();
100+
RelatedEntity relatedEntity = new RelatedEntity();
101+
relatedEntity.relatedCounter = 0;
102+
relatedEntity.main = mainEntity;
103+
mainEntity.mainCounter = 0;
104+
mainEntity.relatedEntity = List.of(relatedEntity);
105+
106+
entityManager.persist(relatedEntity);
107+
entityManager.persist(mainEntity);
108+
109+
transaction.commit();
110+
entityManager.close();
111+
return mainEntity.id;
112+
}
113+
38114
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package org.hibernate.bugs.entity;
2+
3+
import jakarta.persistence.Entity;
4+
import jakarta.persistence.GeneratedValue;
5+
import jakarta.persistence.GenerationType;
6+
import jakarta.persistence.Id;
7+
import jakarta.persistence.OneToMany;
8+
import java.util.List;
9+
10+
@Entity
11+
12+
public class MainEntity {
13+
14+
@Id
15+
@GeneratedValue(strategy = GenerationType.AUTO)
16+
public long id;
17+
18+
@OneToMany(mappedBy = "main")
19+
public List<RelatedEntity> relatedEntity;
20+
21+
public int mainCounter;
22+
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.hibernate.bugs.entity;
2+
3+
import jakarta.persistence.Entity;
4+
import jakarta.persistence.GeneratedValue;
5+
import jakarta.persistence.GenerationType;
6+
import jakarta.persistence.Id;
7+
import jakarta.persistence.ManyToOne;
8+
9+
@Entity
10+
public class RelatedEntity {
11+
12+
@Id
13+
@GeneratedValue(strategy = GenerationType.AUTO)
14+
public long id;
15+
16+
@ManyToOne
17+
public MainEntity main;
18+
19+
public int relatedCounter;
20+
21+
}

orm/hibernate-orm-6/src/test/resources/META-INF/persistence.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
<property name="hibernate.connection.url" value="jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1"/>
1919
<property name="hibernate.connection.username" value="sa"/>
2020

21-
<property name="hibernate.connection.pool_size" value="5"/>
21+
<property name="hibernate.connection.pool_size" value="50"/>
2222

2323
<property name="hibernate.show_sql" value="true"/>
2424
<property name="hibernate.format_sql" value="true"/>

0 commit comments

Comments
 (0)