Unidirectional many-to-many relationships in Grails, and how it could affect the batch performance decisively.

von Xuetao Li

Mapping business domains using GORM (Grails Object Relational Mapping) is in most cases straightforward and uncomplicated to implement.
The documented way to map many-to-many relationships in Grails is to define a hasMany on both sides of the relationship AND having a belongsTo on the owned side: [1]

class Fee {
    static hasMany = [foos:Foo]
class Foo {
    static hasMany = [fees:Fee]
    static belongsTo = Fee

The example given above demonstrates a bidirectional many-to-many association between Fee and Foo. Both sides of the relationship are holding references to the other side. This might be the most common use case.

What if you don't really need references from both sides, but only from one side (unidirectional)? Someone could ask - "Does it make sense to have unidirectional many-to-many? The references are per default lazy loaded and therefore seems to be harmless." - Not in a particular situation.

In a project that is in production since years we have batch jobs for persisting a large number of domain entities into the database. Thanks to the approaches introduced by Ted Naleid [2] the performance of the batches was fine. We are using the service method cleanUpGorm() at regular intervals to release memory usage by the hibernate session:

def cleanUpGorm() {
    def session = sessionFactory.currentSession

Consider the following situation: 

  • There is a many-to-many relationship between Fee and Foo
  • A Foo instance, let's say "foo-1" is referenced by 200,000 Fee instances
  • Batch has inserted some more Fee instances which are also referenced to "foo-1"

In this case, the call to session.clear() was taking minutes after the batch process has inserted 30 Fee instances. With such a performance the batch won't be finished within the time window. We used to have a much better performance and the problem must be fixed for the total changes on that branch to be released.

One of the solutions here is to have a unidirectional many-to-many relationship from Fee to Foo. The result in the giving situation was a performance boost up to 10x faster. The following example shows how to achieve it with GORM:
class Fee {
    static hasMany = [foos:Foo]
class Foo {
    static hasMany = [Fee]

Fee is the owning side and is responsable for persisting relationships. Foo is the owned side and do not have any references to Fee.


Unidirectional many-to-many relationships is supported by hibernate [3] and Grails.
The GORM keyword belongsTo is mandatory for bidirectional, but not for unidirectional many-to-many relationships.
To achieve a unidirectional many-to-many you should define a "hasMany" without references and without belongsTo on the owned side.


© 2006-2024 exensio GmbH
Einstellungen gespeichert


Wir nutzen Cookies auf unserer Website. Einige von ihnen sind essenziell, während andere uns helfen, diese Website und Ihre Erfahrung zu verbessern.

Sie können Ihre Einwilligung jederzeit ändern oder widerrufen, indem Sie auf den Link in der Datenschutzerklärung klicken.

Zu den gesetzlichen Rechenschaftspflichten gehört die Einwilligung (Opt-In) zu protokollieren und archivieren. Aus diesem Grund wird Ihre Opt-In Entscheidung in eine LOG-Datei geschrieben. In dieser Datei werden folgende Daten gespeichert:


  • IP-Adresse des Besuchers
  • Vom Besucher gewählte Datenschutzeinstellung (Privacy Level)
  • Datum und Zeit des Speicherns
  • Domain
You are using an outdated browser. The website may not be displayed correctly. Close