I'm working on a Spring Boot application where I create an order using a createOrder method. Everytime, I encounter the following error:
OrderService
public class OrderService {
OrderRepository orderRepository;
ItemRepository itemRepository;
UserRepository userRepository;
private OrderView mapToOrderView(Order order) {
return OrderView.builder().orderId(order.getOrderId())
.userId(order.getUserId())
.createdTime(order.getCreatedTime())
.updatedTime(order.getUpdatedTime())
.completedTime(order.getCompletedTime())
.orderItems(order.getOrderItems())
.deliveryMethod(order.getDeliveryMethod())
.orderStatus(order.getOrderStatus())
.additionalInstructions(order.getAdditionalInstructions())
.rating(order.getRating())
.feedback(order.getFeedback())
.build();
}
@Transactional
public OrderView createOrder(PostOrderRequest request) {
Order order = Order.builder()
.orderId(UUID.randomUUID())
.userId(request.getUserId())
.createdTime(LocalDateTime.now())
.deliveryMethod(request.getDeliveryMethod())
.orderStatus(OrderStatus.PLACED)
.build();
List<OrderItem> orderItems = mapOrderItems(request.getOrderItems(), order.getOrderId());
order.setOrderItems(orderItems);
order.setUpdatedTime(LocalDateTime.now());
orderRepository.save(order);
return mapToOrderView(order);
}
private List<OrderItem> mapOrderItems(List<OrderItem> itemRequests, UUID orderId) {
if (itemRequests == null || itemRequests.isEmpty()) {
throw new IllegalArgumentException("Order must contain at least one item.");
}
List<OrderItem> orderItems = new ArrayList<>();
for (OrderItem itemRequest : itemRequests) {
Optional<Item> item = itemRepository.findById(itemRequest.getItemId());
if (item.isEmpty()) {
throw new IllegalArgumentException("Item not available: " + itemRequest.getItemId());
}
orderItems.add(OrderItem.builder()
.orderItemId(UUID.randomUUID())
.itemId(item.get().getItemId())
.quantity(itemRequest.getQuantity())
.build());
}
return orderItems;
}
Order.class
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private UUID orderId;
private UUID userId;
@Column(updatable = false, insertable = false)
private LocalDateTime createdTime;
private LocalDateTime updatedTime;
private LocalDateTime completedTime;
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
private List<OrderItem> orderItems;
private DeliveryMethod deliveryMethod;
private OrderStatus orderStatus;
@OneToOne
@JoinColumn(name = "payment_id")
private Payment payment;
private String additionalInstructions;
private int rating;
private String feedback;
@Version
private int version;
}
Error log
"org.springframework.orm.ObjectOptimisticLockingFailureException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [order.mgt.core.model.Order#be58d23c-010b-4f3c-9917-f9aa0df95c4f]The resource you are trying to update has been modified by another transaction.
Hibernate logs
Hibernate:
select
u1_0.user_id,
u1_0.country,
u1_0.county,
u1_0.number,
u1_0.post_code,
u1_0.street_address,
u1_0.street_address2,
u1_0.town,
u1_0.email,
u1_0.phone_number,
u1_0.created_date,
u1_0.name
from
user u1_0
where
u1_0.user_id=?
Hibernate:
select
i1_0.item_id,
i1_0.category,
i1_0.description,
i1_0.image,
i1_0.is_available,
i1_0.name,
i1_0.tag
from
item i1_0
where
i1_0.item_id=?
Hibernate:
select
o1_0.order_id,
o1_0.additional_instructions,
o1_0.completed_time,
o1_0.created_time,
o1_0.delivery_method,
o1_0.feedback,
o1_0.order_status,
p1_0.paymentid,
p1_0.amount,
p1_0.currency,
p1_0.order_id,
p1_0.status,
p1_0.type,
o1_0.rating,
o1_0.updated_time,
o1_0.user_id,
o1_0.version,
oi1_0.order_id,
oi1_0.order_item_id,
c1_0.customization_id,
c1_0.customization_option,
c1_0.price_change,
i1_0.item_id,
i1_0.category,
i1_0.description,
i1_0.image,
i1_0.is_available,
i1_0.name,
i1_0.tag,
oi1_0.item_id,
oi1_0.portion_size,
oi1_0.quantity
from
orders o1_0
left join
payment p1_0
on p1_0.paymentid=o1_0.payment_id
left join
order_item oi1_0
on o1_0.order_id=oi1_0.order_id
left join
customization c1_0
on c1_0.customization_id=oi1_0.customization_id
left join
item i1_0
on i1_0.item_id=oi1_0.item_id2
where
o1_0.order_id=?
Hibernate:
select
o1_0.order_id,
o1_0.additional_instructions,
o1_0.completed_time,
o1_0.created_time,
o1_0.delivery_method,
o1_0.feedback,
o1_0.order_status,
p1_0.paymentid,
p1_0.amount,
p1_0.currency,
p1_0.order_id,
p1_0.status,
p1_0.type,
o1_0.rating,
o1_0.updated_time,
o1_0.user_id,
o1_0.version
from
orders o1_0
left join
payment p1_0
on p1_0.paymentid=o1_0.payment_id
where
o1_0.order_id=?
Any help or suggestions to overcome this issue? I am working on a Spring Boot application that handles order creation and involves multiple database operations, such as fetching user and item details, and saving orders and related entities. I have optimistic locking in place using a @Version field in my entities to handle concurrent updates. The service method responsible for order creation is annotated with @Transactional to ensure all database operations happen within a single transaction
The error occurs because the @Id
field (orderId
) is annotated with @GeneratedValue(strategy = GenerationType.AUTO)
, which means Hibernate automatically generates the value for this field. However, in my service class, iam manually assigning a value to orderId
using UUID.randomUUID()
. This conflict leads to the exception
Hibernate relies on the @GeneratedValue
annotation to automatically manage the orderId
field. When we assign a UUID manually, Hibernate does not recognize it as a managed entity. This results in inconsistencies in the persistence context.
Additionally, manually setting the ID might create conflicts with Hibernate’s expectation of the orderId
lifecycle, causing the optimistic locking failure.
Removing orderId(UUID.randomUUID())
from order Builder works like a charm.