0

I am using GORM standalone (groovyVersion = '2.0.8', grailsVersion = '2.2.4', gormVersion = '1.3.7', h2Version = '1.3.170') and have a database of objects which will be undergoing frequent concurrent modification.

These objects are grouped by one property, 'entry' and have another property 'process_flags' that I need to update. I want to update all of the process_flag settings of a group of the objects defined by having the same entry. (This will indicate to other processes that I am processing this group of objects.)

I presently try code like the following:

List<Item>  res = null
int triesRemaining = 10 // try locking a group this many times
while (res==null && triesRemaining > 0) {
  Item firstItem = Item.findByProcessFlags(Item.ProcessFlags.NEW)
  if (firstItem==null) return null
  res = Item.findAllByEntry(firstItem.entry)
  try {
    Item.withTransaction {transStatus->
      res.each {it->
        if (it.processFlags != Item.ProcessFlags.NEW) {
          throw new StaleObjectStateException(Item.class.toString(),it.id)
        }
        it.processFlags = Item.ProcessFlags.IN_PROCESS
        it.save(flush:true)
      }
    }
  } catch (HibernateOptimisticLockingFailureException e) {
    logger.debug("Caught HibernateOptimisticLockingFailureException. Trying new group.")
    res = null
    triesRemaining--
  }
return res

This results in a exception propagating up the stack, labelled as occurring at the res.each and as a StaleObjectStateException, though I presume is actually a HibernateOptimisticLockingFailureException, as per this discussion: How to handle GORM exceptions. Note that neither the class nor the method in which this code appears is annotated @Transactional.

So my questions are how to best handle this situation in code with frequent concurrent accesses? Is there a way to do it with catching a failure of optimistic locking? Or does this need to be handled with some pessimistic locking? And if so, can it still be handled with dynamic finders?

Community
  • 1
  • 1
Peter N. Steinmetz
  • 1,252
  • 1
  • 15
  • 23
  • One very important item to note. The class PatchedDefaultEventListener, which is in Grails, is logging the exception as an error and then re-throwing it. This shows up in the log and is a bit confusing, because it looks like an exception being caught further along, but is not. The exception being thrown is a HibernateOptimisticLockingFailureException. – Peter N. Steinmetz Jun 05 '14 at 18:43

1 Answers1

0

What you want to do is used a where query. The where method returns a DetachedCriteria instance, that allows you to perform a batch update:

 Item.where { entry == firstItem.entry }
     .updateAll(processFlags: Item.ProcessFlags.IN_PROCESS)
Graeme Rocher
  • 7,985
  • 2
  • 26
  • 37