2017-05-05 23 views
10

Tôi có một ứng dụng còn lại, nơi một trong các tài nguyên có thể được cập nhật. Dưới đây là hai phương pháp có trách nhiệm để đạt được nhiệm vụ này:OptimisticLockException khi sử dụng JPA merge()

  1. updateWithRelatedEntities (String, Store): nhận được id và cửa hàng đối tượng mới được xây dựng bởi deserializing yêu cầu PUT tổ chức nào, đặt phiên bản (sử dụng cho khóa lạc quan) về cập nhật đối tượng và cuộc gọi mới trong giao dịch.

    public Store updateWithRelatedEntities(String id, Store newStore) { 
        Store existingStore = this.get(id); 
    
        newStore.setVersion(existingStore.getVersion()); 
    
        em.getTransaction().begin(); 
        newStore = super.update(id, newStore); 
        em.getTransaction().commit(); 
    
        return newStore; 
    } 
    
  2. cập nhật (String, T): một phương pháp chung để làm một bản cập nhật. Kiểm tra xem id có khớp và thực hiện thao tác hợp nhất hay không.

    public T update(String id, T newObj) { 
        if (newObj == null) { 
        throw new EmptyPayloadException(type.getSimpleName()); 
        } 
    
    
        Type superclass = getClass().getGenericSuperclass(); 
    
        if (superclass instanceof Class) { 
         superclass = ((Class) superclass).getGenericSuperclass(); 
        } 
    
        Class<T> type = (Class<T>) (((ParameterizedType) superclass).getActualTypeArguments()[0]); 
    
        T obj = em.find(type, id); 
    
        if (!newObj.getId().equals(obj.getId())) { 
         throw new IdMismatchException(id, newObj.getId()); 
        } 
    
        return em.merge(newObj); 
    } 
    

Vấn đề là cuộc gọi này: T obj = em.find(type, id); gây nên một bản cập nhật của cửa hàng đối tượng trong cơ sở dữ liệu có nghĩa là chúng tôi nhận OptimisticLockException khi kích hoạt merge (vì các phiên bản hiện nay khác nhau).

Tại sao điều này lại xảy ra? Điều gì sẽ là cách chính xác để đạt được điều này?

Tôi không muốn sao chép các thuộc tính từ newStore đến existingStore và sử dụng existingStore để hợp nhất - theo tôi nghĩ, giải quyết vấn đề khóa lạc quan.

Mã này không chạy trên máy chủ ứng dụng và tôi không sử dụng JTA.

EDIT: Nếu tôi tách CurrentStore trước khi gọi cập nhật, T obj = em.find(type, id); không kích hoạt cập nhật đối tượng cửa hàng để giải quyết vấn đề. Câu hỏi vẫn còn mặc dù - tại sao nó kích hoạt nó khi thực thể không tách rời?

+0

Bạn có hiểu khái niệm về khóa lạc quan không? – Kayaman

+0

Có, tôi hiểu khái niệm và lý do tại sao tôi nhận được lỗi này. Những gì tôi không hiểu là lý do tại sao JPA cập nhật phiên bản khi gọi get (id) mà sau đó dẫn vào OptimistiLockException khi gọi hợp nhất. –

+0

Hình thức 'get (id)' trông như thế nào? – Kayaman

Trả lời

1

Tôi không thể nhìn thấy thực thể của bạn từ mã bạn đã thêm nhưng tôi tin rằng bạn thiếu một số điểm quan trọng với khóa lạc quan ->@Version chú thích trên trường phiên bản. Nếu bạn có trường này trên thực thể của bạn thì vùng chứa sẽ có thể thực hiện quy trình hợp nhất mà không gặp sự cố. Vui lòng xem Optimistic Locking cũng tốt bài viết don't break optimistic locking

+0

Tôi đang sử dụng trường '@ Version', vấn đề là tôi đang cập nhật với một đối tượng mới (được tạo bởi deserializing), vì vậy tôi phải đặt trường' @ Version' theo cách thủ công. –

+0

Tại sao bạn không chỉ deserialize đối tượng và lấy id của nó, làm một 'em.find' và sau đó bạn có thể cập nhật các thực thể thích hợp. Những gì bạn đang làm là kinda hacky .. – galovics

+0

Đó sẽ là một giải pháp, nhưng tôi không thích nó, bởi vì tôi biết những lĩnh vực tôi không muốn sao chép và không phải là cách khác xung quanh. Vì vậy, nếu tôi thêm một trường vào thực thể trong tương lai, tôi sẽ phải nhớ rằng tôi phải thêm trường đó vào một phần khác của codebase. –

Các vấn đề liên quan