Details

    • Type: Sub-task Sub-task
    • Status: Closed
    • Priority: Minor Minor
    • Resolution: Fixed
    • Affects Version/s: 1.0.2
    • Fix Version/s: 1.1-beta1
    • Component/s: Persistence
    • Labels:
      None
    • Environment:
      OSX + Postgres
    • Testcase included:
      yes

      Description

      Grails Pesismistic Locking doesn't work.

      • domainObject.lock() has no effect
      • DomainObject.lock(id) doesn't take longs or Integers

      I've uploaded a test project that demonstrates this. The project uses Postgres and the drives the application through HttpUnit. You'll need to create a db called lockbug to reproduce (or edit DataSource.groovy)

      It appears the only way to actually lock objects in grails is to jump through some hibernate hoops or use a SQL statement (as follows).

      import org.hibernate.SessionFactory
      import org.hibernate.LockMode
      
      class AccountService {
      
          SessionFactory sessionFactory
      
          int incrementWithDynamicLockMethod(String name) {
              Account account = Account.findByName(name)
              account.lock()    // Doesn't lock
              account.balance++
              account.save(flush:true)
              return account.balance
          }
      
          int incrementWithStaticLockMethod(String name) {
              Account account = Account.findByName(name)
              account = Account.lock(account.id) // Throws exception (doesn't take Longs or Strings)
              account.balance++
              account.save(flush:true)
              return account.balance
          }
      
          int incrementWithHibernateLockMethod(String name) {
              Account account = Account.findByName(name)
              sessionFactory.currentSession.lock(account, LockMode.UPGRADE) // Does nothing because account already in the session
              account.balance++
              account.save(flush:true)
              return account.balance        
          }
      
          int incrementWithHibernateLoadMethod(String name) {
              Account account = Account.findByName(name)
              sessionFactory.currentSession.clear() // Need to clear the session to force db load (may be able to use evict in some circumstances)
              account = sessionFactory.currentSession.load(Account.class, account.id, LockMode.UPGRADE)
              account.balance++
              account.save(flush:true)
              return account.balance
          }
      
          int incrementWithPostgresLockStatement(String name) {
              sessionFactory.currentSession.createSQLQuery('LOCK account IN ACCESS EXCLUSIVE MODE').executeUpdate() // Full Table Lock just for example
              Account account = Account.findByName(name)
              account.balance++
              account.save(flush:true)
              return account.balance
          }
      }
      
      1. lockbug.tar.gz
        2.73 MB
        Stephen Cresswell
      2. lockbug.tar.gz
        2.71 MB
        Stephen Cresswell
      3. postgreslogs.tar.gz
        4 kB
        Stephen Cresswell

        Issue Links

          Activity

          Hide
          Graeme Rocher added a comment -

          Call account.discard() before calling Account.lock(..)

          Show
          Graeme Rocher added a comment - Call account.discard() before calling Account.lock(..)
          Hide
          Stephen Cresswell added a comment -

          At least update the grails docs. There's no hint of using grails.discard() prior to obtaining a lock.
          Would also be nice if there were findByNameForUpdate() type methods to prevent an uncessary refresh.

          Show
          Stephen Cresswell added a comment - At least update the grails docs. There's no hint of using grails.discard() prior to obtaining a lock. Would also be nice if there were findByNameForUpdate() type methods to prevent an uncessary refresh.
          Hide
          Graeme Rocher added a comment -

          schedulling to 1.1 so that we can add the mentioned feature

          Show
          Graeme Rocher added a comment - schedulling to 1.1 so that we can add the mentioned feature
          Hide
          Graeme Rocher added a comment -

          Reduced priority of non critical issues which have current workarounds

          Show
          Graeme Rocher added a comment - Reduced priority of non critical issues which have current workarounds
          Hide
          Graeme Rocher added a comment -

          This issue is fixed by GRAILS-3402

          You can now do:

          Account account = Account.findByName(name, [lock:true] )
          
          
          Show
          Graeme Rocher added a comment - This issue is fixed by GRAILS-3402 You can now do: Account account = Account.findByName(name, [lock: true ] )

            People

            • Assignee:
              Graeme Rocher
              Reporter:
              Stephen Cresswell
            • Votes:
              2 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development