23 Aralık 2020 Çarşamba

SpringData @Version Anotasyonu

Giriş
Açıklaması şöyle. JPA ve MongoDB kullanıyorsak Optimistic Concurrency sağlar.
The @Version annotation provides syntax similar to that of JPA in the context of MongoDB and makes sure updates are only applied to documents with a matching version. Therefore, the actual value of the version property is added to the update query in such a way that the update does not have any effect if another operation altered the document in the meantime. In that case, an OptimisticLockingFailureException is thrown.
Şöyle yaparız
@Document
class Person {
  @Id String id;
  String firstname;
  String lastname;
  @Version
  Long version;
}

Person daenerys = template.insert(new Person("Daenerys")); // 1

Person tmp = template.findOne(query(where("id").is(daenerys.getId())), Person.class);// 2

daenerys.setLastname("Targaryen");
template.save(daenerys); // 3

// throws OptimisticLockingFailureException
template.save(tmp); // 4
Açıklaması şöyle
1. Intially insert document. version is set to 0.
2. Load the just inserted document. version is still 0.
3. Update the document with version = 0. Set the lastname and bump version to 1.
4. Try to update the previously loaded document that still has version = 0. 
  The operation fails with an OptimisticLockingFailureException, 
  as the current version is 1.
Örnek
Şöyle yaparız. Burada servis katmanında OptimisticLockingFailureException kendi expception sınıfımız olan ConcurrentUpdateException nesnesine çevriliyor. Controller katmanında ConcurrentUpdateException yakalanırsa HttpStatus.CONFLICT 
döndürülüyor
@Service
public class ItemService {
  @Autowired
  private ItemRepository itemRepository;

  public void updateItemStock(Long itemId, int newStock) {
    try {
      Item item = itemRepository.findById(itemId)
        .orElseThrow(() -> new ItemNotFoundException(itemId));
      item.setStock(newStock);
      itemRepository.save(item);
    } catch (OptimisticLockingFailureException e) {
      throw new ConcurrentUpdateException(
        "The item was updated by another user. Please try again.", e);
    }
  }
}

@RestController
@RequestMapping("/items")
public class ItemController {
  @Autowired
  private ItemService itemService;
    
  @PutMapping("/{itemId}/stock")
  public ResponseEntity<?> updateItemStock(@PathVariable Long itemId, 
                                           @RequestParam int newStock) {
    try {
      itemService.updateItemStock(itemId, newStock);
      return ResponseEntity.ok("Stock updated successfully.");
    } catch (ConcurrentUpdateException e) {
      return ResponseEntity.status(HttpStatus.CONFLICT).body(e.getMessage());
    }
  }
}

Hiç yorum yok:

Yorum Gönder