|
Summary: How to explicitly prevent multiple users from from performing get, put or remove operations with the same key under a transaction.
OverviewIn the pessimistic locking approach, your program must explicitly obtain a lock using a transaction on one or more objects before making any changes. This prevents any other user from making changes to those objects, so you can be sure that committing the operation will succeed. Once changes are completed, the objects are unlocked so that others can make changes to them. Blocking RulesWhen using a transaction with the IMap operations you are essentially locking the object. The following table describes space operation blocking rules when using the Map API. The operations listed on the top ("Operation B") are blocked, or allowed, when performed in conjunction with operations listed on the left ("Operation A").
Get LockA get lock guarantees that an object is not changed while you are looking at it. It is useful when you want to look at an object but not change it. Put LockA put lock guarantees that you are the sole user of an object and that you are looking at the most up-to-date version of an object. It is useful when you want to update an existing object. Remove LockThe remove operation behaves much like the get operation, except that a matching Entry is also removed from the cache. Operations without TransactionIn general, when a space cache is called without a transaction , its scope is limited to the Entry or Entries passed to the operation. Any other cache operations, with or without a transaction, can be executed without any blocking. ExampleThe following code example demonstrates a usage of the pessimistic locking. Get and put calls are performed using transaction 1. Another get and put call are performed under transaction 2. The get and put calls with transaction 2 cannot be performed until transaction 1 is committed: package com.gigaspaces.examples.mappessimistic; import net.jini.core.transaction.Transaction; import net.jini.core.transaction.TransactionFactory; import com.j_spaces.core.client.CacheException; import com.j_spaces.core.client.CacheTimeoutException; import com.j_spaces.core.client.EntryVersionConflictException; import com.j_spaces.core.client.FinderException; import com.j_spaces.core.client.LocalTransactionManager; import com.j_spaces.map.CacheFinder; import com.j_spaces.map.IMap; public class MapPessimisticTest { public static void main(String[] args) { IMap cache1; IMap cache2; try { cache1 = (IMap) CacheFinder .find("rmi://localhost/./mySpace"); cache2 = (IMap) CacheFinder .find("rmi://localhost/./mySpace"); cache1.clear(); cache1.put("key", new MyData("data1")); cache1.setWaitForResponse(5000); cache2.setWaitForResponse(5000); LocalTransactionManager trManager = (LocalTransactionManager) LocalTransactionManager .getInstance(cache1); Transaction txn1 = null; Transaction txn2 = null; // Transactionfactory lease will expire after one minute // (automatic abort / rollback) Transaction.Created tCreated1 = TransactionFactory.create( trManager, 1000 * 60); txn1 = tCreated1.transaction; Transaction.Created tCreated2 = TransactionFactory.create( trManager, 1000 * 60); txn2 = tCreated2.transaction; // put an object into map and commit the transaction System.out.println("Put Object under transaction..."); // both get operation done without Transaction cache1.setTransaction(txn1); MyData value1 = (MyData) cache1.get("key"); System.out.println("tx1 get OK!"); value1.data = "data2"; cache1.put("key", value1); System.out.println("tx1 put OK!"); MyData value2 = null; cache2.setTransaction(txn2); boolean completed = false; while (!completed) { try { value2 = (MyData) cache2.get("key"); System.out.println("tx2 get OK!"); value2.data = "data3"; cache2.put("key", value2); System.out.println("tx2 put OK!"); completed = true; txn2.commit(); System.out.println("tx2 commit!"); } catch (CacheTimeoutException e) { System.out.println(e.getMessage()); txn1.commit(); System.out.println("tx1 commit!"); System.out.println("tx2 Reading key again!"); value2 = (MyData) cache2.get("key"); } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } package com.gigaspaces.examples.mappessimistic; import java.io.Serializable; import com.j_spaces.core.client.MetaDataEntry; public class MyData implements Serializable { public MyData() {} public MyData(String data) { this.data=data; } String data; } The expected output: Put Object under transaction...
tx1 get OK!
tx1 put OK!
Entry 121252961^25^key^0^0 is locked under another transaction. Operation timeout expired.
tx1 commit!
tx2 Reading key again!
tx2 get OK!
tx2 put OK!
tx2 commit!
|
(works on Firefox 2 and Internet Explorer 7)