Sunday, 5 July 2015

Groovy SQL TRANSACTION BOUNDARY

Recently I have been trying to explore the Transaction feature of Groovy SQL.

Groovy SQL really relieves us from all the boiler plate code that we required while setting up JDBC connection and executing CRUD operations.
Querying, Inserting, Updating data, traversing the ResultSets is much smoother with Groovy SQL beacuse of all the various tools it provide and another feature that I cannot stop myself from mentioning out here is the DataSets. They are really handy.

In this tutorial, I am not going to discuss on the above mentioned features, as there are lots of resources in web on those topics.
I got into a scenario, where I need to set the auto commit off for a set of JDBC transaction, so that in case of any failure, I can rollback and in case of everything is fine I can commit, i.e. I want a set of JDBC opeartions to be carried out within a single unit of work, i.e. a transaction.
I found that the JDBC operation carried out within Sql.withTransaction{} closure are well within transaction boundaries, and any exception raised within this bondary will rollback all the operations carried out within closure boundary only.
But what will happen if we want to span that transaction across method boundaries?????

Lets Traverse through the code, Here it is a workaround.
Here I have used HSQLDB for the implementation.
The code is:


class SqlTest {

 static main(args)
 {
  DataSource ds = new JDBCDataSource()
  ds.database = "jdbc:hsqldb:mem:foo"
  ds.user = 'sa'
  ds.password = ''
  Connection con = ds.connection
  Sql sql = new Sql(con)
  sql.execute("create table subha (id integer, name varchar(20) not null)")
  sql.execute("insert into subha values (100,'Subha')")

  /*sql.withTransaction {connection ->
   println "${connection.getClass()}"
   }*/

  try{
   testMethod(sql)
   sql.eachRow("select * from subha")
   {
    println "${it.id}"
    println "${it.name}"
   }

  }
  catch(e)
  {
   sql.eachRow("select * from subha")
   {
    println "${it.id}"
    println "${it.name}"
   }
  }

  finally
  {
   sql.close()
  }
 }

 static def testMethod(Sql sql)
 {
  SubhaModel su = new SubhaModel(subhaID:10000,subhaName:'Puchuuuuu')

  try{

   sql.withTransaction {connection ->
    //connection.setAutoCommit(false)
    //throw new Exception("Okkkkk")
    sql.execute("insert into subha values (103,'Subha133')")
    def people = sql.dataSet("SUBHA")
    people.add(id:104,name:'Subha135')
    people.add(id:105,name:'Subha136')
    //throw new Exception("Okkkkk")
    people.add(id:106,name:'Subha137')
    people.add(id:107,name:'Subha138')

    sql.execute("insert into subha values (?.subhaID,?.subhaName)",su)


    testAgain(sql)

    //throw new Exception("Yoooooo")
    
    people.add(id:111)
    //sql.rollback()

   }


   //sql.commit()
  }
  catch(e)
  {
   //sql.rollback()
  }
 }

 static def testAgain(Sql sql)
 {
  try{

   //sql.withTransaction {
    def people = sql.dataSet("SUBHA")
    people.add(id:999,name:'Subha9999')
    people.add(id:9999,name:'YOOOOO')
    
    //throw new Exception("Yoooooo")
   //}
  }

  catch(e)
  {
   throw new Exception("YooooooAgainnnn")
  }
 }
}


Now, from the above code we can see that within testMethod() we are inserting some data into SUBHA table and there is also a call to testAgain() which again does some insert and all this is happening within the transactional boundary initiated by sql.withTransaction{} closure.

Now, if an exception is raised within this transaction boundary (of testMethod()) then the whole transaction is rolled back , i.e. none of the data gets inserted even the one within testAgain().

Now if we want the called method to be within the same Transactional Boundary then any exception raised within the called method needs to propgated to the calling transaction boundary, if some how the the Excetion is not propagated to the calling transaction boundary, then the calling Transaction will be considered to be successful and they are committed and in the called method just before the point the Exception is raised, all the statements are committed.

When the Exception is propagated with the help of throws clause in the ctach block of testAgain(), then the transaction is rolled back.

Now if we wrap the operations of the called method within transactional boundary (i.e. uncomment the sql.withTransaction { } closure from within testAgain and comment the throw clause within the catch) and an Exception is thrown even not propagated also then the calling transaction and the called transaction both are rolled back. But one catch is: if the transaction in testAgain() is over then all the all the statements starting from the calling transaction within testMethod() to this point are considered to be successful and are commited, and after this when the control moves to the calling transaction within testMethod() and then some exception arises WITHIN within testMethod() then the whole transaction is not rolled back.

This is the way by which we can propagate transaction across methods in groovy.
Keep sharing your Views and Opinions and untill next Time keep Coding and keep Sharing....
View Subhankar Paul's profile on LinkedIn

Groovy Listeners with AST

Recently while I was exploring Groovy features, I came across a very interesting component, i.e Listeners in Groovy
I will try to explain it with an example:

We have the following interface:


interface SpeakListener {

 void spoke(SpeakEvent event)
 void spoken(SpeakEvent event,String c)
 void spokeString(String str)
}

the Event class

class SpeakEvent {

 String name,origin
}

and a Listener class
i.e.

class GroovyListener {
 
 @groovy.beans.ListenerList
 List lisList
 
 String name
 
 void sayHello()
 {
  fireSpoke(new SpeakEvent(origin: name, name: 'Hello Groovy world!'))
  fireSpoken(new SpeakEvent(origin: name, name: 'Hello Groovy world!--Spoken'),"Mic")
  fireSpokeString("Mickey")
 }
 
}

The SpeakListener & SpeakEvent are just normal interfaces and class respectively. We will soon explore their role in this play :-)

The first thing that is consequential is the annotation @groovy.beans.ListenerList. We have annotated a list of type SpeakListener with @groovy.beans.ListenerList.
So the question arises what does it do?

Now when we add annotation to a List of a specified type which happens to play the role of a Listener adds the following methods to the class:

1) void addSpeakListener(SpeakListener listener)
2) void removeSpeakListener(SpeakListener listener)
3) void SpeakListener[] getSpeakListeners()


And for each method in the Listener Class i.e. SpeakListener there is fire method like
4) void fireSpoke(SpeakEvent event)
5) fireSpoken(SpeakEvent event, String c)
6) fireSpoken(SpeakEvent event, String c)
Here there are only 3 fire methods as there are only three methods in the Listener.
As it is clearly evident, that these fire methods has signature as the original methods.

Now here comes the usage part,
When we will add Speak Listeners to lisList, by adding each implementation of the SpeakListener interface and invoke the sayHello() method then the corresponding implenetation will be invoked, i.e. if the sayHello() has got only fireSpoke call, and we have added two different implementation of the SpeakListener to the lisList, then the spoke(SpeakEvent event) implementation from those two listeners in the lisList will be invoked. i.e.


class GroovyListenerTest {

 static main(args)
 {
  def listener = new GroovyListener(name:'Subha')
  
  /**
   * Implementing Speak Listener interface
   * by prividing implementations of indivudual methods
   */
  
  
  listener.addSpeakListener([spoke:{event -> println "${event.name} has Origin ${event.origin}"},spoken:{event,s -> println "${event.name} has Origin ${event.origin} for $s"},spokeString:{str -> println "The String is $str"}] as SpeakListener)
  //listener.addSpeakListener([spoken:{event -> println "${event.name} has Origin(Spoken) ${event.origin}"}] as SpeakListener)
  
  /**
   * Implementing Interface By providing the 
   * same definitions across all the methods
   * of the interface
   * 
   */
  
  def shout = {Object[] args1  -> println "$args1 has  New Origin"} as SpeakListener
  listener.addSpeakListener(shout)
  
  listener.sayHello()
 }
}

The output in the above case will be:

Hello Groovy world! has Origin Subha
[com.subha.model.SpeakEvent@41d9a8] has New Origin

Assuming that the sayHello() has only the fireSpoke(....) method invoked.
So,the SpeakEvent instance that is being used in the sayHello() is being passed to the registered Listeners added to the lisList.

Interesting right......
That's all on Groovy Listeners. Please share your views and comments.
View Subhankar Paul's profile on LinkedIn