How can I achieve the equivalent of this code:
tx.begin(); Widget w = em.find(Widget.class, 1L, LockModeType.PESSIMISTIC_WRITE); w.decrementBy(4); em.flush(); tx.commit();
... but using Spring and Spring-Data-JPA annotations?
The basis of my existing code is:
@Service @Transactional(readOnly = true) public class WidgetServiceImpl implements WidgetService { /** The spring-data widget repository which extends CrudRepository<Widget, Long>. */ @Autowired private WidgetRepository repo; @Transactional(readOnly = false) public void updateWidgetStock(Long id, int count) { Widget w = this.repo.findOne(id); w.decrementBy(4); this.repo.save(w); } }
But I don't know how to specify that everything in the updateWidgetStock
method should be done with a pessimistic lock set.
There is a Spring Data JPA annotation org.springframework.data.jpa.repository.Lock
which allows you to set a LockModeType
, but I don't know if it's valid to put it on the updateWidgetStock
method. It sounds more like an annotation on the WidgetRepository
, because the Javadoc says:
org.springframework.data.jpa.repository
@Target(value=METHOD)
@Retention(value=RUNTIME)
@Documented
public @interface Lock
Annotation used to specify the LockModeType to be used when executing the query. It will be evaluated when using Query on a query method or if you derive the query from the method name.
... so that doesn't seem to be helpful.
How can I make my updateWidgetStock()
method execute with LockModeType.PESSIMISTIC_WRITE
set?
In order to use optimistic locking, we need to have an entity including a property with @Version annotation. While using it, each transaction that reads data holds the value of the version property. Before the transaction wants to make an update, it checks the version property again.
To specify a lock on a custom query method of a Spring Data JPA repository, we can annotate the method with @Lock and specify the required lock mode type: @Lock(LockModeType. OPTIMISTIC_FORCE_INCREMENT) @Query("SELECT c FROM Customer c WHERE c.
We can configure Spring Data JPA by following these steps: Enable Spring Data JPA by annotating the PersistenceContext class with the @EnableJpaRepositories annotation. Configure the base packages that are scanned when Spring Data JPA creates implementations for our repository interfaces.
A lock with LockModeType. PESSIMISTIC_WRITE can be used when querying data and there is a high likelihood of deadlock or update failure among concurrent updating transactions. The persistence implementation must support use of locks of type LockModeType.
@Lock
is supported on CRUD methods as of version 1.6 of Spring Data JPA (in fact, there's already a milestone available). See this ticket for more details.
With that version you simply declare the following:
interface WidgetRepository extends Repository<Widget, Long> { @Lock(LockModeType.PESSIMISTIC_WRITE) Widget findOne(Long id); }
This will cause the CRUD implementation part of the backing repository proxy to apply the configured LockModeType
to the find(…)
call on the EntityManager
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With