Concurrency PENGEMBANGAN APLIKASI ENTERPRISE © NIKO IBRAHIM FAKULTAS TEKNOLOGI INFORMASI UNIVERSITAS KRISTEN MARANATHA
What’s inside? Versioning Optimistic Locking
Pessismistic Locking
Kasus Concurrency Pada saat entitas diakses secara concurrent
(bersamaan/simultan), maka aplikasi kita harus mampu menangani masalah locking. Contoh kasus:
Satu aplikasi 2 methods Kedua methods ini dijalankan pada waktu yang bersamaan Method A: update $2 Method B: update $5
Masalah di JPA Yang akan menjadi “pemenang” dari kedua method tadi
adalah yang terakhir di-”commit” Tetapi hal ini tidak dispesifikasikan di dalam JPA Hal yang umum dilakukan adalah mekanisme locking di dalam database, yaitu me-lock baris/row yang sedang diakses oleh perintah SQL Untuk itulah, JPA 2.0 menyediakan dua mekanisme locking:
Optimistic Locking Pessimistic Locking
Optimistic Vs Pessimistic Locking Optimistic locking didasarkan pada asumsi bahwa
kebanyakan transaksi database tidak terjadi konflik dengan transaksi lainnya, sehingga memungkinkan concurrency untuk ‘sesantai’ mungkin pada saat terjadi eksekusi transaksi. Pessimistic locking didasarkan pada asumsi sebaliknya. Jadi, locking akan dilakukan terhadap resource sebelum terjadi eksekusi apapun terhadap resource tsb. Contoh kasus: menyebrang jalan raya di saat sepi (optimistic: langsung menyebrang) atau ramai (pessimistic: pasti hati-hati sebelum menyebrang) Mana yang lebih bahaya?
EntityManager Methods to Lock Entities Method
Description
T find(Class entityClass, Object primaryKey,LockModeType lockMode)
Searches for an entity of the specified class and primary key and locks it with respect to the specified lock type
void lock(Object entity, LockModeType lockMode)
Locks an entity instance that is contained in the persistence context with the specified lock mode type
void refresh(Object entity, LockModeType lockMode)
Refreshes the state of the instance from the database, overwriting changes made to the entity, if any, and locks it with respect to the given lock mode type
Query Method to Lock JPQL Queries Method
Description
Query setLockMode(LockModeType lockMode)
Sets the lock mode type to be used for the query execution
LockModeType OPTIMISTIC: Uses optimistic locking OPTIMISTIC_FORCE_INCREMENT: Uses optimistic locking
and forces an increment to the entity’s version column PESSIMISTIC_READ: Uses pessimistic locking without the need to reread the data at the end of the transaction to obtain a lock PESSIMISTIC_WRITE: Uses pessimistic locking and forces serialization among transactions attempting to update the entity PESSIMISTIC_FORCE_INCREMENT: Uses pessimistic locking and forces an increment to the entity’s version column NONE: Specifies no locking mechanism should be used
Contoh Penggunaan Locking Secara Manual
Book book = em.find(Book.class, 12); // Lock to raise the price em.lock(book, LockModeType.PESSIMISTIC); book.raisePriceByTwoDollars(); Or you can read and lock: Book book = em.find(Book.class, 12, LockModeType.PESSIMISTIC); // The book is already locked, raise the price book.raisePriceByTwoDollars();
Penggunaan Versioning JPA menggunakan mekanisme penomoran untuk
memberikan version pada entitas. Jadi, ketika kita melakukan persist (save) suatu entitas untuk pertama kalinya, maka entitas tsb akan mendapatkan version nomor 1. Kemudian, apabila kita melakukan update suatu atribut dan meng-commit perubahan ini ke database, maka version entitas akan berubah menjadi nomor 2, dst. Versioning ini akan terus berubah setiap kali terjadi perubahan terhadap entitas.
Bagaimana caranya? Untuk melakukan versioning, entitas harus memiliki
atribut yang akan digunakan untuk menyimpan nomor version, dan harus diberikan annotation @Version. Nomor version ini kemudian dipetakan menjadi sebuah kolom di dalam tabel database. Tipe atribut yang dapat digunakan untuk versioning adalah int, Integer, short Short, long, Long, atau Timestamp.
The Book Entity with a @Version Annotation
@Entity public class Book { @Id @GeneratedValue private Long id; @Version private Integer version; private String title; private Float price; private String description; private String isbn; private Integer nbOfPage; private Boolean illustrations; // Constructors, getters, setters }
Transactions tx1 and tx2 Updating the Price of a Book Concurrently Book book = new Book("H2G2", 21f, "Best IT book", "123-456", 321, false); tx.begin(); em.persist(book); tx.commit(); assertEquals(1, book.getVersion()); // TRUE tx.begin(); book.raisePriceByTwoDollars(); tx.commit(); assertEquals(2, book.getVersion()); // TRUE The version attribute is not required but is recommended when the
entity can be concurrently modified by more than one process or thread. Versioning is the core of optimistic locking and provides protection for infrequent concurrent entity modification. In fact, an entity is automatically enabled for optimistic locking if it has a property mapped with a @Version annotation.
Revisit Optimistic Vs Pesimistic Locking Optimistic Locking: optimistic locking is based on the fact that database transactions don’t conflict with one other.
the decision to acquire a lock on the entity is actually made at the end of the transaction. Transactions that would cause this constraint to be violated result in an OptimisticLockException being thrown and the transaction marked for rollback. How would you throw an OptimisticLockException? Either by explicitly locking the entity (with the lock or the find methods that you saw passing a LockModeType) or by letting the persistence provider check the attribute annotated with @Version. Optimistic locking is a useful performance optimization that offloads work that would otherwise be required of the database and is an alternative to pessimistic locking, which requires lowlevel database locking.
OptimisticLockException thrown on transaction tx2
Note: Without an attributed annotated with @Version, the entity
manager will not be able to do optimistic locking.
Pessismitic Locking Pessimistic locking is based on an assumption that is the opposite of
that for optimistic locking, because a lock is eagerly obtained on the entity before operating on it. This is very resource restrictive and results in significant performance degradation, as a database lock is held using a SELECT ... FOR UPDATE SQL statement to read data. This is an effective mechanism to ensure that two clients do not modify the same row at the same time, but requires expensive, lowlevel checks inside the database. Transactions that would cause this constraint to be violated result in a PessimisticLockException being thrown and the transaction marked for rollback. But in some applications with a higher risk of contentions, pessimist locking may be more appropriate, as the database lock is immediately obtained as opposed to the often late failure of optimistic transactions. Pessimistic locking may be applied to entities that do not contain the annotated @Version attribute.
Contoh Penggunaan Pessimistic Locking
Book book = em.find(Book.class, 12); // Lock to raise the price em.lock(book, LockModeType.PESSIMISTIC); book.raisePriceByTwoDollars(); Or you can read and lock: Book book = em.find(Book.class, 12, LockModeType.PESSIMISTIC); // The book is already locked, raise the price book.raisePriceByTwoDollars();
Kesimpulan Pada perkuliahan ini Anda telah mendapatkan
pengetahuan mengenai prinsip concurrency terhadap entitas Penangangan concurrency pada entitas dilakukan dengan cara locking, baik secara pesimis atau optimis