Skip to content

Commit 31511c4

Browse files
committed
Retry version-less optimistic locking
1 parent c5481e6 commit 31511c4

File tree

9 files changed

+224
-222
lines changed

9 files changed

+224
-222
lines changed

HibernateSpringBootVersionlessOptimisticLocking/pom.xml renamed to HibernateSpringBootRetryVersionlessOptimisticLocking/pom.xml

+3-5
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@
44
<modelVersion>4.0.0</modelVersion>
55

66
<groupId>com.jpa</groupId>
7-
<artifactId>jpa</artifactId>
7+
<artifactId>HibernateSpringBootRetryVersionlessOptimisticLocking</artifactId>
88
<version>1.0</version>
99
<packaging>jar</packaging>
1010

11-
<name>jpa</name>
11+
<name>HibernateSpringBootRetryVersionlessOptimisticLocking</name>
1212
<description>JPA project for Spring Boot</description>
1313

1414
<parent>
1515
<groupId>org.springframework.boot</groupId>
1616
<artifactId>spring-boot-starter-parent</artifactId>
17-
<version>2.0.5.RELEASE</version>
17+
<version>2.1.4.RELEASE</version>
1818
<relativePath/> <!-- lookup parent from repository -->
1919
</parent>
2020

@@ -62,6 +62,4 @@
6262
</plugin>
6363
</plugins>
6464
</build>
65-
66-
6765
</project>
+7-8
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,30 @@
1-
package com.jpa;
1+
package com.bookstore;
22

3+
import com.bookstore.service.InventoryService;
34
import com.vladmihalcea.concurrent.aop.OptimisticConcurrencyControlAspect;
45
import org.springframework.boot.ApplicationRunner;
56
import org.springframework.boot.SpringApplication;
67
import org.springframework.boot.autoconfigure.SpringBootApplication;
78
import org.springframework.context.annotation.Bean;
8-
import org.springframework.context.annotation.Configuration;
99
import org.springframework.context.annotation.EnableAspectJAutoProxy;
1010

11-
@Configuration
12-
@EnableAspectJAutoProxy
1311
@SpringBootApplication
14-
public class RetryOptimisticLockApplication {
12+
@EnableAspectJAutoProxy
13+
public class MainApplication {
1514

1615
private final InventoryService inventoryService;
1716

18-
public RetryOptimisticLockApplication(InventoryService inventoryService) {
17+
public MainApplication(InventoryService inventoryService) {
1918
this.inventoryService = inventoryService;
2019
}
2120

2221
public static void main(String[] args) {
23-
SpringApplication.run(RetryOptimisticLockApplication.class, args);
22+
SpringApplication.run(MainApplication.class, args);
2423
}
2524

2625
@Bean
2726
public OptimisticConcurrencyControlAspect optimisticConcurrencyControlAspect() {
28-
return new com.vladmihalcea.concurrent.aop.OptimisticConcurrencyControlAspect();
27+
return new OptimisticConcurrencyControlAspect();
2928
}
3029

3130
@Bean
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,46 @@
1-
package com.jpa;
2-
3-
import java.io.Serializable;
4-
import javax.persistence.Entity;
5-
import javax.persistence.Id;
6-
import org.hibernate.annotations.DynamicUpdate;
7-
import org.hibernate.annotations.OptimisticLockType;
8-
import org.hibernate.annotations.OptimisticLocking;
9-
10-
@Entity
11-
@DynamicUpdate
12-
@OptimisticLocking(type = OptimisticLockType.DIRTY)
13-
public class Inventory implements Serializable {
14-
15-
private static final long serialVersionUID = 1L;
16-
17-
@Id
18-
private Long id;
19-
20-
private String name;
21-
private int quantity;
22-
23-
public Long getId() {
24-
return id;
25-
}
26-
27-
public void setId(Long id) {
28-
this.id = id;
29-
}
30-
31-
public String getName() {
32-
return name;
33-
}
34-
35-
public void setName(String name) {
36-
this.name = name;
37-
}
38-
39-
public int getQuantity() {
40-
return quantity;
41-
}
42-
43-
public void setQuantity(int quantity) {
44-
this.quantity = quantity;
45-
}
46-
}
1+
package com.bookstore.entity;
2+
3+
import java.io.Serializable;
4+
import javax.persistence.Entity;
5+
import javax.persistence.Id;
6+
import org.hibernate.annotations.DynamicUpdate;
7+
import org.hibernate.annotations.OptimisticLockType;
8+
import org.hibernate.annotations.OptimisticLocking;
9+
10+
@Entity
11+
@DynamicUpdate
12+
@OptimisticLocking(type = OptimisticLockType.DIRTY)
13+
public class Inventory implements Serializable {
14+
15+
private static final long serialVersionUID = 1L;
16+
17+
@Id
18+
private Long id;
19+
20+
private String title;
21+
private int quantity;
22+
23+
public Long getId() {
24+
return id;
25+
}
26+
27+
public void setId(Long id) {
28+
this.id = id;
29+
}
30+
31+
public String getTitle() {
32+
return title;
33+
}
34+
35+
public void setTitle(String title) {
36+
this.title = title;
37+
}
38+
39+
public int getQuantity() {
40+
return quantity;
41+
}
42+
43+
public void setQuantity(int quantity) {
44+
this.quantity = quantity;
45+
}
46+
}
Original file line numberDiff line numberDiff line change
@@ -1,90 +1,91 @@
1-
package com.jpa;
2-
3-
import com.vladmihalcea.concurrent.Retry;
4-
import java.io.Serializable;
5-
import java.util.logging.Level;
6-
import java.util.logging.Logger;
7-
import javax.persistence.EntityManager;
8-
import javax.persistence.EntityManagerFactory;
9-
import javax.persistence.EntityTransaction;
10-
import javax.persistence.OptimisticLockException;
11-
import org.springframework.beans.factory.annotation.Autowired;
12-
import org.springframework.context.ApplicationContext;
13-
import org.springframework.context.annotation.Scope;
14-
import org.springframework.stereotype.Repository;
15-
16-
@Repository
17-
@Scope("prototype")
18-
public class InventoryRepository implements Serializable, Runnable {
19-
20-
private final int quantity;
21-
private final int delay;
22-
23-
@Autowired
24-
private ApplicationContext applicationContext;
25-
26-
private static final Logger logger = Logger.getLogger(InventoryRepository.class.getName());
27-
28-
public InventoryRepository(int quantity, int delay) {
29-
this.quantity = quantity;
30-
this.delay = delay;
31-
}
32-
33-
@Override
34-
@Retry(times = 10, on = OptimisticLockException.class)
35-
public void run() {
36-
37-
EntityManagerFactory entityManagerFactory
38-
= applicationContext.getBean(EntityManagerFactory.class);
39-
40-
EntityManager entityManager = entityManagerFactory.createEntityManager();
41-
42-
EntityTransaction entityTransaction = entityManager.getTransaction();
43-
44-
try {
45-
entityTransaction.begin();
46-
47-
Inventory inventory = entityManager.find(Inventory.class, 1L);
48-
49-
if ((inventory.getQuantity() - quantity) >= 0) {
50-
inventory.setQuantity(inventory.getQuantity() - quantity);
51-
}
52-
53-
try {
54-
Thread.sleep(delay);
55-
} catch (InterruptedException ex) {
56-
Thread.currentThread().interrupt();
57-
}
58-
59-
entityTransaction.commit();
60-
61-
logger.info("Transaction committed ...");
62-
} catch (RuntimeException e) {
63-
64-
if (is(e, OptimisticLockException.class)) {
65-
logger.log(Level.INFO, "OptimisticLockException has occured ...");
66-
logger.log(Level.INFO, "Retry mechanism enter into the scene ...");
67-
}
68-
69-
if (entityTransaction != null && entityTransaction.isActive()) {
70-
entityTransaction.rollback();
71-
}
72-
73-
throw (e);
74-
}
75-
}
76-
77-
public static <T extends Throwable> boolean is(Throwable exception, Class<T> type) {
78-
Throwable unwrappedException = exception;
79-
80-
while (unwrappedException != null) {
81-
if (type.isInstance(unwrappedException)) {
82-
return true;
83-
}
84-
85-
unwrappedException = unwrappedException.getCause();
86-
}
87-
88-
return false;
89-
}
90-
}
1+
package com.bookstore.repository;
2+
3+
import com.bookstore.entity.Inventory;
4+
import com.vladmihalcea.concurrent.Retry;
5+
import java.io.Serializable;
6+
import java.util.logging.Level;
7+
import java.util.logging.Logger;
8+
import javax.persistence.EntityManager;
9+
import javax.persistence.EntityManagerFactory;
10+
import javax.persistence.EntityTransaction;
11+
import javax.persistence.OptimisticLockException;
12+
import org.springframework.beans.factory.annotation.Autowired;
13+
import org.springframework.context.ApplicationContext;
14+
import org.springframework.context.annotation.Scope;
15+
import org.springframework.stereotype.Repository;
16+
17+
@Repository
18+
@Scope("prototype")
19+
public class InventoryRepository implements Serializable, Runnable {
20+
21+
private final int quantity;
22+
private final int delay;
23+
24+
@Autowired
25+
private ApplicationContext applicationContext;
26+
27+
private static final Logger logger = Logger.getLogger(InventoryRepository.class.getName());
28+
29+
public InventoryRepository(int quantity, int delay) {
30+
this.quantity = quantity;
31+
this.delay = delay;
32+
}
33+
34+
@Override
35+
@Retry(times = 10, on = OptimisticLockException.class)
36+
public void run() {
37+
38+
EntityManagerFactory entityManagerFactory
39+
= applicationContext.getBean(EntityManagerFactory.class);
40+
41+
EntityManager entityManager = entityManagerFactory.createEntityManager();
42+
43+
EntityTransaction entityTransaction = entityManager.getTransaction();
44+
45+
try {
46+
entityTransaction.begin();
47+
48+
Inventory inventory = entityManager.find(Inventory.class, 1L);
49+
50+
if ((inventory.getQuantity() - quantity) >= 0) {
51+
inventory.setQuantity(inventory.getQuantity() - quantity);
52+
}
53+
54+
try {
55+
Thread.sleep(delay);
56+
} catch (InterruptedException ex) {
57+
Thread.currentThread().interrupt();
58+
}
59+
60+
entityTransaction.commit();
61+
62+
logger.info("Transaction committed ...");
63+
} catch (RuntimeException e) {
64+
65+
if (is(e, OptimisticLockException.class)) {
66+
logger.log(Level.INFO, "OptimisticLockException has occured ...");
67+
logger.log(Level.INFO, "Retry mechanism enter into the scene ...");
68+
}
69+
70+
if (entityTransaction != null && entityTransaction.isActive()) {
71+
entityTransaction.rollback();
72+
}
73+
74+
throw (e);
75+
}
76+
}
77+
78+
public static <T extends Throwable> boolean is(Throwable exception, Class<T> type) {
79+
Throwable unwrappedException = exception;
80+
81+
while (unwrappedException != null) {
82+
if (type.isInstance(unwrappedException)) {
83+
return true;
84+
}
85+
86+
unwrappedException = unwrappedException.getCause();
87+
}
88+
89+
return false;
90+
}
91+
}

0 commit comments

Comments
 (0)