Showing posts with label Groovy. Show all posts
Showing posts with label Groovy. Show all posts

Saturday, June 30, 2012

GORM - False Sense of Simplicity

While maintaining some code recently, I came across what seemed to be some particularly evil code.  It was a service method that used a Grails Criteria Query to fish out some objects from the DB.  These were then converted to Data Transfer Objects (DTO) to be serialized for use in a GWT client.  It went something like :


def myObjects = Domain.findAllBySomething(thing)
....
....
....
myObjects.each{obj ->
  def dto = new Dto()
  dto.property = obj.innerDomain.property
  dto.propertyTwo = obj.innerDomain.anotherDomain.property
  dtos << dto
}

It seems fairly innocent but try telling that the database.  Each call on any of the properties within obj that are themselves domains resulted in another database call.  Creating the DTO above resulted in about 3 queries just to set two properties.  This might not sound too bad, but imagine if myObjects contains 1,000 or so objects.... not the best strategy.  The actual code I was maintaining was typically returning about 1,000 results and this resulted in about 13,000 queries running on the database.  This was a user driven event so it could be happening quite a lot.  This was obviously terrible for performance.  Of course there is an argument to use paging and caching of results etc. but that's a different blog post.  Long story short, a colleague (who I won't name for social reasons) and I were able to get the 13,000 queries down to 25 for the entire service method by just configuring the query correctly.

The main point here is the difference between eager and lazy fetching.  A long time ago, Grails' default fetching strategy was eager.  This basically meant that when you queried for domains, using dynamic finders or criteria, your object model would return fully populated.  Unfortunately this could also result in you returning the entire database in one query.  Not good.

Around about Grails 1.0.4,  the default fetching strategy was changed to lazy.  This meant that your object model returned partially populated, that is, proxy objects with only their id's, were returned for properties that were themselves domains.  When you called for a property on one of these proxies, Grails would request it from the database.  All this happened pretty transparently to the user.

Grails provides many ways of forcing earger fetching.  It can be done in the domain mappings and in the domain itself by setting the fetch mode.  It can also be done at a query level which I am more in favour of.  Setting on the domain itself is too much of a commitment in my opinion as you can never imagine all use cases at time of coding.  I will illustrate setting it in dynamic finders with the following domains :


class Customer {

  String name
  Account account

  static constraints = {
    account unique: true, nullable: false, blank: false
    name nullable: false, blank: false
  }
}

class Account {
  static belongsTo = [owner: Customer]

  Long accountNumber

  static constraints = {
    accountNumber min: 0l, nullable: false, unique: true
  }
}

class BankingTransaction {

  Long transactionNumber
  BigDecimal amount
  Account fromAccount
  Account toAccount

  static constraints = {
    transactionNumber min: 0l, unique: true, nullable: false
    fromAccount nullable: false, validator: {Account thisFromAccount, BankingTransaction thisTransaction ->
      if (thisFromAccount?.accountNumber == thisTransaction?.toAccount?.accountNumber) {
        return false//cannot have a transaction to the same account... probably
      }
    }
    toAccount nullable: false
    amount nullable: false
  }

  BankingTransactionDTO toBankingTransactionDTO() {
    def dto = new BankingTransactionDTO()
    dto.with {//probably better ways of doing this but this illustrated the example
      transactionNumber = this.transactionNumber
      amount = this.amount
      fromCustomersName = fromAccount.owner.name
      toCustomersName = toAccount.owner.name
    }
    return dto
  }

}

So to illustrate the lazy and eager fetching I wrote some tests that were bootstrapped on a MySQL database.  First we need to set up some test data and an additional Grooy Sql connection to run some status queries on our DB.


class BankingTransactionTests {

  Sql sql
  SessionFactory sessionFactory
  BankingTransactionService bankingTransactionService

  @Before
  void setUp() {
    BankingTransaction.withNewSession {session ->
      100.times {num ->
        new Customer(name: "Customer ${num}", account: new Account(accountNumber: num)).save(failOnError: true)
      }
    }

    BankingTransaction.withNewSession {session ->
      final allCustomers = Customer.list()
      def generousCustomer = allCustomers[0]
      allCustomers[1..-1].eachWithIndex {customer, index ->
        new BankingTransaction(fromAccount: generousCustomer.account, toAccount: customer.account, transactionNumber: index, amount: index * 100).save(failOnError: true)
      }
    }
    sql = new Sql(sessionFactory.currentSession.connection())
    sql.metaClass.getNumberOfSelects = {->
      return delegate.rows('SHOW STATUS LIKE "Com_select"')[0].Value as Long
    }
  }

....
}

I won't go into the details, it is just an integration test, the code is on GitHub anyway for the forever curious.  So first off lets do a simple test that queries for all BankingTransactions.


  @Test
  void testSimpleQuery() {
    //get the current number of selects in this session
    def numberOfQueriesBeforeTest = sql.numberOfSelects

    //carry out the query
    final transaction = BankingTransaction.list()//1 query

    //now calculate the number of queries
    def numberOfQueriesAfterTest = sql.numberOfSelects
    final numberOfSelects = numberOfQueriesAfterTest - numberOfQueriesBeforeTest

    //is it what we expect??
    assert numberOfSelects == 1
  }
We run the test, and huzzah, test passes. As we would expect BankingTransaction.list() is a simple select query.

OK, now lets access some properties on the first BankingTransaction


  @Test
  void testSimplePropertyAccess() {
    //get the current number of selects in this session
    def numberOfQueriesBeforeTest = sql.numberOfSelects

    //carry out the query
    final transaction = BankingTransaction.list()[0]
    def fromAccountNumber = transaction.fromAccount.accountNumber
    def fromAccountCustomerName = transaction.fromAccount.owner.name

    //now calculate the number of queries
    def numberOfQueriesAfterTest = sql.numberOfSelects
    final numberOfSelects = numberOfQueriesAfterTest - numberOfQueriesBeforeTest

    //is it what we expect??
    assert numberOfSelects == 1
  }

Uh oh, test fails with :

Assertion failed: 

assert numberOfSelects == 1
       |               |
       3               false


Looking closely at the test we can see the three queries, the first is the the call the list(), the second is the call to fromAccount and the third, the call to fromAccount.owner.

OK, so, lets fix the query by setting the fetch mode to join in the query.


  @Test
  void testSimplePropertyAccess() {
    //get the current number of selects in this session
    def numberOfQueriesBeforeTest = sql.numberOfSelects

    def queryParams = [fetch: [fromAccount: 'join', 'fromAccount.owner': 'join']]
    //carry out the query
    final transaction = BankingTransaction.list(queryParams)[0]
    def fromAccountNumber = transaction.fromAccount.accountNumber
    def fromAccountCustomerName = transaction.fromAccount.owner.name

    //now calculate the number of queries
    def numberOfQueriesAfterTest = sql.numberOfSelects
    final numberOfSelects = numberOfQueriesAfterTest - numberOfQueriesBeforeTest

    //is it what we expect??
    assert numberOfSelects == 1
  }


Test passes! Sweet! This is because we told GORM to fetch the associated domains using a join. I suppose we should look at a more real work example. Suppose we have a BankingTransactionService with the following method :
class BankingTransactionService {

  Collection retrieveTransactions() {
    def transactions = BankingTransaction.list()
    return transactions.collect {it.toBankingTransactionDTO()}
  }

}


With the following test :

  @Test
  void testBankingService() {
    //get the current number of selects in this session
    def numberOfQueriesBeforeTest = sql.numberOfSelects

    //carry out the query
    def dtos = bankingTransactionService.retrieveTransactions()

    //now calculate the number of queries
    def numberOfQueriesAfterTest = sql.numberOfSelects
    final numberOfSelects = numberOfQueriesAfterTest - numberOfQueriesBeforeTest

    //is it what we expect??
    assert numberOfSelects == 1
  }


We run the test, and eh... not looking good :

Assertion failed: 

assert numberOfSelects == 1
       |               |
       201             false


Hmmm 201 queries, this will not please the performance junkies at all. What is happening in toBankingTransactionDTO() is that as the objects are created a query happens each time a property that is a domain is accessed. These slowly build up in the first level cache reducing the amount of queries, but I think we can do better.

Let's go all out and reduce the number of queries to 1 for this service method.  It's gonna be a long road.... not really :


  Collection retrieveTransactions() {
    final queryParams = [fetch: [
            fromAccount: 'join',
            toAccount: 'join',
            'toAccount.owner': 'join',
            'fromAccount.owner': 'join']
    ]
    def transactions = BankingTransaction.list(queryParams)
    return transactions.collect {it.toBankingTransactionDTO()}
  }


Test passes. There we go, 201 queries to 1. Not really that much work, just don't take the simplicity provided by GORM for granted or you will have some angry DBA's on your tail... you have been warned!

Slán

Code on GitHub.

Monday, January 24, 2011

Quick Groovy Script! Google Geocoding!

Nice little script for parsing the Google Ceocoding Web Service. (Groovy 1.7.5)


/**
Simple Script to parse the google geocode web service
http://code.google.com/apis/maps/documentation/geocoding/
*/
def url = new URL('http://maps.googleapis.com/maps/api/geocode/xml?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&sensor=true')
def geoCodeResult = new XmlParser().parseText(url.getText())
def lat = geoCodeResult.result.geometry.location.lat.text()
def lng = geoCodeResult.result.geometry.location.lng.text()
println lat
println lng


Outputs :
37.4216227
-122.0840263

Tuesday, August 4, 2009

Pretty Printing Groovy's StreamingMarkupBuilder

Unfortunately, Groovy's StreamingMarkupBuilder will not output indented xml due to its streaming nature. However, never fear, JTidy is here to save the day!

JTidy is a project hosted here on sourceforge and it is a pretty nice HTML/XML pretty printer. It also seems to check your HTML for errors, which is cool! Examples are lacking however so I thought I would share my findings with this example:


public class JTidyExample {

def tidyMeUp(String singleLine) {
StringWriter writer = new StringWriter()
Tidy tidy = new Tidy()
tidy.identity {
setEscapeCdata(false)//leave cdata untouched
setIndentCdata(true)//indent the CData
setXmlTags(true)//working with xml not html
parse(new StringReader(singleLine), writer)
}
writer.toString()
}

def createMarkUp() {
String cData = "<![CDATA[hello]]>"
StreamingMarkupBuilder xml = new StreamingMarkupBuilder();
def person1 = {
person(id: 1) {
firstName("John")
lastName("Doe")
data_labels {
mkp.yieldUnescaped(cData)
}
}
}
def personList = {
people {
out << person1
}
}
xml.bind(personList).toString()
}

def static main(def args) {
def example = new JTidyExample()
def singleLine = example.createMarkUp()
println "Before: \n ${singleLine}"
println "After: \n ${example.tidyMeUp(singleLine)}"
}

}



The following is output:


Before:

<people><person id='1'><firstName>John</firstName><lastName>Doe</lastName><data_labels><![CDATA[hello]]></data_labels></person></people>

Tidy (vers 26-Sep-2004) Parsing "InputStream"
no warnings or errors were found

After:

<people>
<person id='1'>
<firstName>John</firstName>
<lastName>Doe</lastName>
<data_labels>
<![CDATA[hello]]>
</data_labels>
</person>
</people>



Here we can see that our XML is now nicely indented. Want some more??? Check out Scott Davis' Groovy Recipes, it has a pretty sweet XML section!

UPDATE: Check out Paul Kings comments where he suggests using groovy.xml.XmlUtil.serialize(xml.bind(personList)). Sweet!

Friday, July 24, 2009

Grails Transactions In Brief

OK so first ever blog post, lets keep things short!

I was playing around with transactions in Grails as part of a project a while ago, bearing in mind I have no Spring experience, I was a little worried it might be complicated. Need I worry??? Lord no! Grails to the rescue once again, however there is one 'Gotcha' that I feel is worth putting out there, hence me writing this 'blog'.

Basically transactions are a facet of Grails (obtained from Spring I think) that allow us to roll back database writes if an exception occurs mid-method making our databases cleaner than.... hmm.. don't want to write an offensive metaphor in my first post so lets leave it at clean :)

Suppose we have the following method in our service:

static transactional = true

def serviceMethod(params1,params2){

def domain1 = new Domain()
domain1.save()

def domain2 = new Domain()
domain2.save()//Exception thrown here
}




So because this is transactional, when the exception is thrown while saving domain2, domain1 should be deleted from the database (well that was my assumption). However this is NOT the case. After some reading, it seems that the roll back will only occur if the exception thrown is of type RuntimeException. This means that we would have to catch an exception and then throw a RuntimeException, which I think makes this sort of transactional behavior pointless... if we know where exceptions are going to occur we could just roll back ourselves maybe.... I'm sure there's a reason :)

However, all is not lost!! We can take finer grained control of transactions using the Domain.withTransaction{} closure where Domain is the name of a domain in our project. To use this, we must set the service's transactional property to false. Here's how it works:


static transactional = false

def serviceMethod(params1,params2){

Domain.withTransaction{tx ->

def domain1 = new Domain()
domain1.save()

def domain2 = new Domain()
domain2.save()//Exception thrown here

}

}


Now when any exception is thrown at domain2.save() (probably before it), the transaction is rolled back and domain one is deleted. We can also roll back programmically by using tx.setRollbackOnly(). Actually saying domain one is deleted probably isn't correct because they are never persisted, just saved to the session... i think!

Anyways, I hope this helps some people new to dealing with transactions in Grails. Feedback is welcome and also if anyone knows how to make my source code indent properly, by all means share :)

John