cancel
Showing results for 
Search instead for 
Did you mean: 

Activiti process variable version and Optimistic Locking Exception

silverhoof1
Champ in-the-making
Champ in-the-making
I totally understand to avoid multiple thread concurrently access the same variable is necessary.
But in my case, I found some weird behavior of the optimistic locking system.
I found that when I have a program issue an Task Query like this:
taskService.createTaskQuery().taskAssignee("SomeGuy").includeProcessVariables().list()

The process engine automatically updated the ver_ column in ACT_GE_BYTEARRAY table. If two people query the same task at the same time, one of them get following exception:
org.activiti.engine.ActivitiOptimisticLockingException: ByteArrayEntity[id=16067, name=xxxx, size=834361] was updated by another transaction concurrently

The problem is, I never intended to update the variables. The use case is just show more task information in our customized task list using process variables and a template. Why upgrade version when reading variables from process instance? I assumed the correct behavior is doing this during the write time when I set variables back to the process instance.
9 REPLIES 9

silverhoof1
Champ in-the-making
Champ in-the-making
And I have multiple variables in the process instance, only one of them's version is getting upgraded each time I call:
List<Task> tasks =  taskService.createTaskQuery().taskId("xxxxx").includeProcessVariables().list()
That is very very weird!!

frederikherema1
Star Contributor
Star Contributor
So you get a variable-update when doing a query? That's indeed strange… I'll take a look, having write-operations in a query is not good. I'll keep you posted on the progress.

yes, I have a simple test case just do the call:
  @Test
  @Rollback(true)
  public void testFetchWithVar(){
  List<Task> tasks =  taskService.createTaskQuery().taskId("19063").includeProcessVariables().list();
  }

And even rollback is set to true, the version is still upgraded…
Very confusing behavior and totally not acceptable because a lot of client may open their task list UI and will call this concurrently which may result in Optimistic Lock Error.

frederikherema1
Star Contributor
Star Contributor
Can you share the kind of serializable class you're using? Are you 100% sure that the serialised form of one instance of such a variable is consistent across multiple saves, when NO instance values are changes? Because, when such a variable is loaded from the context, it's temporarily kept "under a close eye" of the engine. When the context closes (so when all variables/tasks have been gathered and are about to be returned from the .list() call on the query) the actual serialised byte-array is compared with the existing one. In case they have changed, an update will be done.

Make sure that the serialisable value marks all irrelevant fields as "private transient" and that no funny stuff happens Smiley Wink

silverhoof1
Champ in-the-making
Champ in-the-making
I have a HashMap in that Serializable object.
Will this cause the problem?

frederikherema1
Star Contributor
Star Contributor
That's indeed an issue. Hashmap uses keys that are based on the virtual adress of an object (hashkey) in the VM. In case this gets serialised/deserialized, the hashes for the keys will likely change, resulting in a "different" byte-stream in the end.

What is the use case of having a map persisted?

silverhoof1
Champ in-the-making
Champ in-the-making
If I make the map transient. When I deserialize old one from process variable. What will happen?
A new instance of the new version of the class get created and reserialized without the HashMap field and persist to that process variable?

frederikherema1
Star Contributor
Star Contributor
The main question is WHY you want to have a hashmap as a variable? If you want to store key-values pairs, why not just use seperate variables? If you want to store a key-value-mapping, make sure you use a map-implementation that WILL NOT change any serialized bytes, when not changed.

If you really want key-value stored in a single variable, I suggest using a JSON-string (stored as a byte-array)…

Thanks… I was running in the same issue, problem solved, +1 for you answer