|
Summary: How to you write applications under the assumption that put operations may fail, if the updated object is changed by someone else since it was read.
OverviewWith optimistic locking, you write your program under the assumption that a put operation has a chance of failing, if your updated object is changed by someone else since you read it. Optimistic locking offers higher concurrency and better performance than pessimistic locking. It also avoids deadlocks. Optimistic data locking relies on the idea that data remains unmodified while it is away from the server. As a simple example, consider how you would update client details. The customer details are stored in an object, and if a client wants to update them, it will first need to get the object from the cache. The data is not locked, and other clients can have access to it simultaneously, thus ensuring a scalable system. Pessimistic locking may be less suitable for real-time systems than optimistic locking, because the cache runs best with short term transactions. Optimistic locking also has a big advantage when you may want to read a large number of objects but update only a few of them; or when it is unlikely that objects you want to work with will be updated by others. In general, optimistic locking ensures that updated objects are the most recent ones, while improving the coherency of system behavior. Flow
while (!completed) { try { cache.put("key", value2); completed = true; } catch (CacheTimeoutException e) { value2 = cache.get("key); } catch (CacheException e) { if (e.getCause() instanceof EntryVersionConflictException) { value2 = (MyData) cache.get("key"); } } } ExampleSee example for the optimistic locking usage: package com.gigaspaces.examples.mapoptimistic; import com.j_spaces.core.client.CacheException; import com.j_spaces.core.client.EntryVersionConflictException; import com.j_spaces.core.client.FinderException; import com.j_spaces.map.CacheFinder; import com.j_spaces.map.IMap; public class MapoptimisticTest { public static void main(String[] args) { IMap cache; try { cache = (IMap) CacheFinder .find("rmi://localhost/./mySpace?versioned=true"); cache.clear(); cache.put("key", new MyData("data1")); MyData value1 = (MyData) cache.get("key"); MyData value2 = (MyData) cache.get("key"); value1.data = "data2"; cache.put("key", value1); value2.data = "data3"; boolean completed = false; while (!completed) { try { cache.put("key", value2); completed = true; System.out.println("updated key OK!"); } catch (CacheException e) { if (e.getCause() instanceof EntryVersionConflictException) { System.out.println(e.getCause().getMessage()); System.out.println("Reading key again!"); value2 = (MyData) cache.get("key"); } } } } catch (FinderException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } package com.gigaspaces.examples.mapoptimistic; import java.io.Serializable; public class MyData implements Serializable { public MyData() {} public MyData(String data) { this.data=data; } String data; } |
(works on Firefox 2 and Internet Explorer 7)