When a Grails domain class is reloaded after a change, the Hibernate plugin for Grails verifies the domain class reloaded successfully by calling its count() method. Unfortunately, while somewhat rare, it is possible to have a domain class mapped to a very large table (or a view that joins very large tables) where a count query does not return quickly. Normally, this situation would not occur in development (which is when a reload would happen), but depending on the environment it is possible that large amounts of data are available in development/test in order to help simulate the load/data variety of production. This can cause issues for your domain class reload and can also be the source of sadness for your DBAs who are wondering why the application developers are sending select count(*) queries to a view that joins billion-row tables.

The code responsible for the count call is org.codehaus.groovy.grails.plugins.orm.hibernate.HibernatePluginSupport around line 394 (in Grails 2.0.4):

///////// Around line 392 in HibernatePluginSupport

// Verify that the reload worked by executing a GORM method. If it failed try again
try {
    event.source.count()
} catch (MissingMethodException mme) {

   MappingContext mappingContext = ctx.getBean("grailsDomainClassMappingContext", MappingContext)
   final sessionFactory = ctx.getBean("sessionFactory", SessionFactory)
   final txMgr = ctx.getBean("transactionManager", HibernateTransactionManager)
   final datastore = new HibernateDatastore(mappingContext, sessionFactory, ctx, application.config)
   def enhancer = new HibernateGormEnhancer(datastore, txMgr, application)
   def entity = mappingContext.getPersistentEntity(event.source.name)
   if (entity.javaClass.getAnnotation(Enhanced) == null) {
      enhancer.enhance entity
   }
   else {
      enhancer.enhance entity, true
   }

}

A dummy class which can simulate the behavior can be found here

/**
 * Domain class representing a class mapped to a really big table or view
 * which does not return a total count quickly.
 * 
 * When this class is modified, HibernatePluginSupport will call count() which 
 * could potentially hang our auto reload and also make our DBAs unhappy.  
 * 
 * We can potentially just override count() in classes like these to return 
 * something like 0 or -1 and assume that developers know they should not be 
 * calling count() on a domain class like this.
 */
class SlowCount {

  static mapping = {
    table 'really_big_table_or_view'
  }

  static int count() {
    println 'Slow count called'
    return 0
  }
}

After you load up Grails, if you change the SlowCount domain class (e.g. change return 0 to return 1), you will see the console print out ‘Slow count called’. If you had not overwritten the count method, by default it would attempt to get the number of rows in the table. If this domain class was mapped to a large table/view, it would potentially hang on this call and use up database resources.

To avoid this problem, you could simply override the count method and return 0, potentially also logging a message saying that the method should only be called during a reload in development. If you have many domain classes in this situation, potentially there are other ways to do something similar in one place (e.g. BootStrap.groovy).