SlideShare a Scribd company logo
1 of 36
Grails
Services, Transactions & Async calls
Service
Service
Business logic goes in services.
Don’t use controllers to do any heavy lifting. They are designed only for controlling application flow and
doing data marshaling. All your data access and business logic should happen in transactional
services.
Also avoid much logic in Domain classes. Validation logic there can be limited to basic constraints and
basic postUpdate and postCreate methods.
Create Service
grails> create-service com.netflix.Contract
| Created file grails-app/services/com/netflix/ContractService.groovy
| Created file test/unit/com/netflix/ContractServiceTests.groovy
package com.netflix
class ContractService {
def serviceMethod() {
}
}
Session vs Transaction
User Session: Corresponds to time within which the user is logged in to the system.
Hibernate Session: Associated with JDBC Connection.
Hibernate Transaction: ACID compliant boundary for unit of work.
Scope
> singleton (default), prototype, request, session
class SomeUsefulService {
// this is a request scoped service
static scope = 'request'
}
Service Injection
class ContractController {
ContractService contractService
...
}
No need for AutoWire annotation.
Command Objects
@grails.validation.Validateable
class LoginCommand {
def loginService
String username
String password
static constraints = {
username validator: { val, obj ->
obj.loginService.canLogin(obj.username, obj.password)
}
}
}
Transaction
@Transactional annotation
Service methods are Transactional by default. However best practice is to add @Transactional
annotation to each service
Transaction annotation is similar to Spring’s @Transactional annotation
The @Transactional annotation on the class ensures that all public methods in a service are
transactional.
Annotating a service method (and not at class) with @Transactional disables the default Grails
transactional behavior for that method. so if you use any annotations you must annotate all methods
that require transactions.
Example
import grails.transaction.Transactional
@Transactional
class BookService {
@Transactional(readOnly = true)
def listBooks() {
Book.list()
}
def updateBook() {
// …
}
}
No Transaction & ReadOnly
@NonTransactional
class EmailService {
//OR static transactional = false
….
}
@Transactional(readOnly = true)
class ReportService {
….
}
withTransaction
package com.netflix
class ContractService {
// turn off automatic transaction management
static transactional = false
void someServiceMethod() {
Contract.withTransaction {TransactionStatus tx ->
// do some work with the database….
// if the transaction needs to be rolled back, call setRollbackOnly()
tx.setRollbackOnly()
}
}
}
Savepoint
def save() {
Album.withTransaction { status ->
def album = Album.get(params.id)
album.title = "Changed Title"
album.save(flush:true)
def savepoint = status.createSavepoint()
...
// something goes wrong
if(hasSomethingGoneWrong()) {
status.rollbackToSavepoint(savepoint)
// do something else
...
} } }
Transaction Propagation :(
// Doesn’t work well without additional configuration
@Transactional
void someMethod(...) {
// do some work ...
storeAuditData(...)
}
@Transactional(propagation=Propagation.REQUIRES_NEW)
void storeAuditData(...) {
//
}
http://techbus.safaribooksonline.com/book/programming/9781449324513/4dot-
spring/_transactional_services_html
Error Handling
Exceptions and Validations
class AuthorService {
void updateAge(id, int age) {
def author = Author.get(id)
author.age = age
if (author.isTooOld()) {
throw new AuthorException("too old", author)
}
if (!author.validate()) {
throw new ValidationException("Author is not valid", author.errors)
}
}
}
Exception on Save
def p = Person.get(1)
try {
p.save(failOnError: true)
}
catch (ValidationException e) {
// deal with exception
p.errors.allErrors.each {
println it
}
}
LazyInitializationException
When a transaction is rolled back the Hibernate session used by GORM is cleared. This means any
objects within the session become detached and accessing uninitialized lazy-loaded collections will
lead to LazyInitializationException
class AuthorController {
def authorService
def updateAge() {
try {
authorService.updateAge(params.id, params.int("age"))
} catch(e) {
render "Author books ${e.author.books}"
}
} }
Solution...
class AuthorService {
void updateAge(id, int age) {
def author = Author.findById(id, [fetch:[books:"eager"]])
author.age = age
if (author.isTooOld()) {
throw new AuthorException("too old", author)
}
}
}
Sample
Asynchronous
Various ways...
● Event mechanism using Platform Core
plugin
● JMS Messaging Queues Plugin
● Quartz scheduling Plugin
● Asynchronous Programming
Asynchronous - Promise
import static java.util.concurrent.TimeUnit.*
import static grails.async.Promises.*
Promise p = Promises.task {
// Long running task
}
p.onError { Throwable err ->
println "An error occured ${err.message}"
}
p.onComplete { result ->
println "Promise returned $result"
}
Synchronous - Promise
import static java.util.concurrent.TimeUnit.*
import static grails.async.Promises.*
Promise p = task {
// Long running task
}
…. other tasks
// block until result is called
def result = p.get()
// block for the specified time
def result = p.get(1,MINUTES)
PromiseList
import static grails.async.Promises.*
import grails.async.PromiseList
PromiseList promiseList = tasks([{ 2 * 2 }, { 4 * 4}, { 8 * 8 }])
//... some other processes
assert [4,16,64] == promiseList.get()
PromiseMap
import grails.async.*
PromiseMap map = new PromiseMap()
map['one'] = { 2 * 2 }
map['two'] = { 4 * 4 }
map['three'] = { 8 * 8 }
//Async call
map.onComplete { Map results ->
assert [one:4,two:16,three:64] == results
}
DelegateAsync Transformation
//Sync service
class BookService {
List<Book> findBooks(String title) {
// implementation
}
}
//Async Service
import grails.async.*
class AsyncBookService {
@DelegateAsync BookService bookService
}
DelegateAsync call
//Async service call
AsyncBookService asyncBookService
def findBooks(String title) {
asyncBookService.findBooks(title)
.onComplete { List results ->
println "Books = ${results}"
}
}
Asynchronous GORM
import static grails.async.Promises.*
Person.async.list().onComplete { List results ->
println "Got people = ${results}"
}
PromiseList p = Person.async.getAll(1L, 2L, 3L)
List results = p.get()
Promise p1 = Person.async.findByFirstName("Homer")
Promise p2 = Person.async.findByFirstName("Bart")
Promise p3 = Person.async.findByFirstName("Barney")
results = waitAll(p1, p2, p3)
Async and the Session
When using GORM async each promise is executed in a different thread. Since the Hibernate session
is not concurrency safe, a new session is bound per thread.
This means you cannot save objects returned from asynchronous queries without first merging them
back into session.
def promise = Person.async.findByFirstName("Homer")
def person = promise.get()
person.merge()
person.firstName = "Bart"
In general it is not recommended to read and write objects in different threads and you should avoid
this technique unless absolutely necessary. Also fetch the dependent objects eagerly to avoid
LazyInitializationException
Quartz
plugins {
...
compile ":quartz:1.0.1"
...
}
//New commands
grails create-job
grails install-quartz-config
grails create-job com.netflix.SupplierImport
spock
Testing Services

More Related Content

What's hot

RESTful services on IBM Domino/XWork
RESTful services on IBM Domino/XWorkRESTful services on IBM Domino/XWork
RESTful services on IBM Domino/XWork
John Dalsgaard
 
JavaScript: Variables and Functions
JavaScript: Variables and FunctionsJavaScript: Variables and Functions
JavaScript: Variables and Functions
Jussi Pohjolainen
 

What's hot (20)

RESTful services on IBM Domino/XWork
RESTful services on IBM Domino/XWorkRESTful services on IBM Domino/XWork
RESTful services on IBM Domino/XWork
 
Java script
Java scriptJava script
Java script
 
Log4 J
Log4 JLog4 J
Log4 J
 
Introduction to RxJS
Introduction to RxJSIntroduction to RxJS
Introduction to RxJS
 
Learn flask in 90mins
Learn flask in 90minsLearn flask in 90mins
Learn flask in 90mins
 
JDBC - JPA - Spring Data
JDBC - JPA - Spring DataJDBC - JPA - Spring Data
JDBC - JPA - Spring Data
 
IBM Lotus Domino Domain Monitoring (DDM)
IBM Lotus Domino Domain Monitoring (DDM)IBM Lotus Domino Domain Monitoring (DDM)
IBM Lotus Domino Domain Monitoring (DDM)
 
Graal and Truffle: One VM to Rule Them All
Graal and Truffle: One VM to Rule Them AllGraal and Truffle: One VM to Rule Them All
Graal and Truffle: One VM to Rule Them All
 
Express js
Express jsExpress js
Express js
 
Go Programming Language by Google
Go Programming Language by GoogleGo Programming Language by Google
Go Programming Language by Google
 
JAVA NIO
JAVA NIOJAVA NIO
JAVA NIO
 
IBM Domino / IBM Notes Performance Tuning
IBM Domino / IBM Notes Performance Tuning IBM Domino / IBM Notes Performance Tuning
IBM Domino / IBM Notes Performance Tuning
 
JavaScript: Variables and Functions
JavaScript: Variables and FunctionsJavaScript: Variables and Functions
JavaScript: Variables and Functions
 
Lotusphere 2007 BP301 Advanced Object Oriented Programming for LotusScript
Lotusphere 2007 BP301 Advanced Object Oriented Programming for LotusScriptLotusphere 2007 BP301 Advanced Object Oriented Programming for LotusScript
Lotusphere 2007 BP301 Advanced Object Oriented Programming for LotusScript
 
Engage2022 - Domino Admin Tips
Engage2022 - Domino Admin TipsEngage2022 - Domino Admin Tips
Engage2022 - Domino Admin Tips
 
HCL Sametime V11 installation - tips
HCL Sametime V11 installation - tipsHCL Sametime V11 installation - tips
HCL Sametime V11 installation - tips
 
JUnit 4
JUnit 4JUnit 4
JUnit 4
 
Write microservice in golang
Write microservice in golangWrite microservice in golang
Write microservice in golang
 
Migrate your Sametime Server to LDAP Authentication (Admincamp 2013)
Migrate your Sametime Server to LDAP Authentication (Admincamp 2013)Migrate your Sametime Server to LDAP Authentication (Admincamp 2013)
Migrate your Sametime Server to LDAP Authentication (Admincamp 2013)
 
Grails object relational mapping: GORM
Grails object relational mapping: GORMGrails object relational mapping: GORM
Grails object relational mapping: GORM
 

Similar to Grails transactions

Advanced iOS Build Mechanics, Sebastien Pouliot
Advanced iOS Build Mechanics, Sebastien PouliotAdvanced iOS Build Mechanics, Sebastien Pouliot
Advanced iOS Build Mechanics, Sebastien Pouliot
Xamarin
 

Similar to Grails transactions (20)

Job Queue in Golang
Job Queue in GolangJob Queue in Golang
Job Queue in Golang
 
GDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with easeGDG Devfest 2019 - Build go kit microservices at kubernetes with ease
GDG Devfest 2019 - Build go kit microservices at kubernetes with ease
 
Server Side Swift: Vapor
Server Side Swift: VaporServer Side Swift: Vapor
Server Side Swift: Vapor
 
Scheduling tasks the human way - Brad Wood - ITB2021
Scheduling tasks the human way -  Brad Wood - ITB2021Scheduling tasks the human way -  Brad Wood - ITB2021
Scheduling tasks the human way - Brad Wood - ITB2021
 
如何透過 Go-kit 快速搭建微服務架構應用程式實戰
如何透過 Go-kit 快速搭建微服務架構應用程式實戰如何透過 Go-kit 快速搭建微服務架構應用程式實戰
如何透過 Go-kit 快速搭建微服務架構應用程式實戰
 
gRPC in Go
gRPC in GogRPC in Go
gRPC in Go
 
Async Server Rendering in React+Redux at NYTimes (redux-taxi)
Async Server Rendering in React+Redux at NYTimes (redux-taxi)Async Server Rendering in React+Redux at NYTimes (redux-taxi)
Async Server Rendering in React+Redux at NYTimes (redux-taxi)
 
Think Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJSThink Async: Asynchronous Patterns in NodeJS
Think Async: Asynchronous Patterns in NodeJS
 
Advanced iOS Build Mechanics, Sebastien Pouliot
Advanced iOS Build Mechanics, Sebastien PouliotAdvanced iOS Build Mechanics, Sebastien Pouliot
Advanced iOS Build Mechanics, Sebastien Pouliot
 
用 Go 語言打造多台機器 Scale 架構
用 Go 語言打造多台機器 Scale 架構用 Go 語言打造多台機器 Scale 架構
用 Go 語言打造多台機器 Scale 架構
 
Finagle and Java Service Framework at Pinterest
Finagle and Java Service Framework at PinterestFinagle and Java Service Framework at Pinterest
Finagle and Java Service Framework at Pinterest
 
Writing Docker monitoring agent with Go
Writing Docker monitoring agent with GoWriting Docker monitoring agent with Go
Writing Docker monitoring agent with Go
 
The Ring programming language version 1.5.4 book - Part 8 of 185
The Ring programming language version 1.5.4 book - Part 8 of 185The Ring programming language version 1.5.4 book - Part 8 of 185
The Ring programming language version 1.5.4 book - Part 8 of 185
 
Kitura Todolist tutorial
Kitura Todolist tutorialKitura Todolist tutorial
Kitura Todolist tutorial
 
h-ubu - CDI in JavaScript
h-ubu - CDI in JavaScripth-ubu - CDI in JavaScript
h-ubu - CDI in JavaScript
 
Architecting Alive Apps
Architecting Alive AppsArchitecting Alive Apps
Architecting Alive Apps
 
こわくないよ❤️ Playframeworkソースコードリーディング入門
こわくないよ❤️ Playframeworkソースコードリーディング入門こわくないよ❤️ Playframeworkソースコードリーディング入門
こわくないよ❤️ Playframeworkソースコードリーディング入門
 
Workshop: Async and Parallel in C#
Workshop: Async and Parallel in C#Workshop: Async and Parallel in C#
Workshop: Async and Parallel in C#
 
OSGi ecosystems compared on Apache Karaf - Christian Schneider
OSGi ecosystems compared on Apache Karaf - Christian SchneiderOSGi ecosystems compared on Apache Karaf - Christian Schneider
OSGi ecosystems compared on Apache Karaf - Christian Schneider
 
How to perform debounce in react
How to perform debounce in reactHow to perform debounce in react
How to perform debounce in react
 

Recently uploaded

TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
mohitmore19
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
VishalKumarJha10
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
Health
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
9953056974 Low Rate Call Girls In Saket, Delhi NCR
 

Recently uploaded (20)

TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
SHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions PresentationSHRMPro HRMS Software Solutions Presentation
SHRMPro HRMS Software Solutions Presentation
 
Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...Chinsurah Escorts ☎️8617697112  Starting From 5K to 15K High Profile Escorts ...
Chinsurah Escorts ☎️8617697112 Starting From 5K to 15K High Profile Escorts ...
 
VTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learnVTU technical seminar 8Th Sem on Scikit-learn
VTU technical seminar 8Th Sem on Scikit-learn
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdfintroduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
introduction-to-automotive Andoid os-csimmonds-ndctechtown-2021.pdf
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
Crypto Cloud Review - How To Earn Up To $500 Per DAY Of Bitcoin 100% On AutoP...
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
Generic or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisionsGeneric or specific? Making sensible software design decisions
Generic or specific? Making sensible software design decisions
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 

Grails transactions

  • 3. Service Business logic goes in services. Don’t use controllers to do any heavy lifting. They are designed only for controlling application flow and doing data marshaling. All your data access and business logic should happen in transactional services. Also avoid much logic in Domain classes. Validation logic there can be limited to basic constraints and basic postUpdate and postCreate methods.
  • 4. Create Service grails> create-service com.netflix.Contract | Created file grails-app/services/com/netflix/ContractService.groovy | Created file test/unit/com/netflix/ContractServiceTests.groovy package com.netflix class ContractService { def serviceMethod() { } }
  • 5. Session vs Transaction User Session: Corresponds to time within which the user is logged in to the system. Hibernate Session: Associated with JDBC Connection. Hibernate Transaction: ACID compliant boundary for unit of work.
  • 6. Scope > singleton (default), prototype, request, session class SomeUsefulService { // this is a request scoped service static scope = 'request' }
  • 7. Service Injection class ContractController { ContractService contractService ... } No need for AutoWire annotation.
  • 8. Command Objects @grails.validation.Validateable class LoginCommand { def loginService String username String password static constraints = { username validator: { val, obj -> obj.loginService.canLogin(obj.username, obj.password) } } }
  • 10. @Transactional annotation Service methods are Transactional by default. However best practice is to add @Transactional annotation to each service Transaction annotation is similar to Spring’s @Transactional annotation The @Transactional annotation on the class ensures that all public methods in a service are transactional. Annotating a service method (and not at class) with @Transactional disables the default Grails transactional behavior for that method. so if you use any annotations you must annotate all methods that require transactions.
  • 11. Example import grails.transaction.Transactional @Transactional class BookService { @Transactional(readOnly = true) def listBooks() { Book.list() } def updateBook() { // … } }
  • 12. No Transaction & ReadOnly @NonTransactional class EmailService { //OR static transactional = false …. } @Transactional(readOnly = true) class ReportService { …. }
  • 13. withTransaction package com.netflix class ContractService { // turn off automatic transaction management static transactional = false void someServiceMethod() { Contract.withTransaction {TransactionStatus tx -> // do some work with the database…. // if the transaction needs to be rolled back, call setRollbackOnly() tx.setRollbackOnly() } } }
  • 14. Savepoint def save() { Album.withTransaction { status -> def album = Album.get(params.id) album.title = "Changed Title" album.save(flush:true) def savepoint = status.createSavepoint() ... // something goes wrong if(hasSomethingGoneWrong()) { status.rollbackToSavepoint(savepoint) // do something else ... } } }
  • 15. Transaction Propagation :( // Doesn’t work well without additional configuration @Transactional void someMethod(...) { // do some work ... storeAuditData(...) } @Transactional(propagation=Propagation.REQUIRES_NEW) void storeAuditData(...) { // } http://techbus.safaribooksonline.com/book/programming/9781449324513/4dot- spring/_transactional_services_html
  • 17. Exceptions and Validations class AuthorService { void updateAge(id, int age) { def author = Author.get(id) author.age = age if (author.isTooOld()) { throw new AuthorException("too old", author) } if (!author.validate()) { throw new ValidationException("Author is not valid", author.errors) } } }
  • 18. Exception on Save def p = Person.get(1) try { p.save(failOnError: true) } catch (ValidationException e) { // deal with exception p.errors.allErrors.each { println it } }
  • 19. LazyInitializationException When a transaction is rolled back the Hibernate session used by GORM is cleared. This means any objects within the session become detached and accessing uninitialized lazy-loaded collections will lead to LazyInitializationException class AuthorController { def authorService def updateAge() { try { authorService.updateAge(params.id, params.int("age")) } catch(e) { render "Author books ${e.author.books}" } } }
  • 20. Solution... class AuthorService { void updateAge(id, int age) { def author = Author.findById(id, [fetch:[books:"eager"]]) author.age = age if (author.isTooOld()) { throw new AuthorException("too old", author) } } }
  • 22.
  • 23.
  • 25. Various ways... ● Event mechanism using Platform Core plugin ● JMS Messaging Queues Plugin ● Quartz scheduling Plugin ● Asynchronous Programming
  • 26. Asynchronous - Promise import static java.util.concurrent.TimeUnit.* import static grails.async.Promises.* Promise p = Promises.task { // Long running task } p.onError { Throwable err -> println "An error occured ${err.message}" } p.onComplete { result -> println "Promise returned $result" }
  • 27. Synchronous - Promise import static java.util.concurrent.TimeUnit.* import static grails.async.Promises.* Promise p = task { // Long running task } …. other tasks // block until result is called def result = p.get() // block for the specified time def result = p.get(1,MINUTES)
  • 28. PromiseList import static grails.async.Promises.* import grails.async.PromiseList PromiseList promiseList = tasks([{ 2 * 2 }, { 4 * 4}, { 8 * 8 }]) //... some other processes assert [4,16,64] == promiseList.get()
  • 29. PromiseMap import grails.async.* PromiseMap map = new PromiseMap() map['one'] = { 2 * 2 } map['two'] = { 4 * 4 } map['three'] = { 8 * 8 } //Async call map.onComplete { Map results -> assert [one:4,two:16,three:64] == results }
  • 30. DelegateAsync Transformation //Sync service class BookService { List<Book> findBooks(String title) { // implementation } } //Async Service import grails.async.* class AsyncBookService { @DelegateAsync BookService bookService }
  • 31. DelegateAsync call //Async service call AsyncBookService asyncBookService def findBooks(String title) { asyncBookService.findBooks(title) .onComplete { List results -> println "Books = ${results}" } }
  • 32. Asynchronous GORM import static grails.async.Promises.* Person.async.list().onComplete { List results -> println "Got people = ${results}" } PromiseList p = Person.async.getAll(1L, 2L, 3L) List results = p.get() Promise p1 = Person.async.findByFirstName("Homer") Promise p2 = Person.async.findByFirstName("Bart") Promise p3 = Person.async.findByFirstName("Barney") results = waitAll(p1, p2, p3)
  • 33. Async and the Session When using GORM async each promise is executed in a different thread. Since the Hibernate session is not concurrency safe, a new session is bound per thread. This means you cannot save objects returned from asynchronous queries without first merging them back into session. def promise = Person.async.findByFirstName("Homer") def person = promise.get() person.merge() person.firstName = "Bart" In general it is not recommended to read and write objects in different threads and you should avoid this technique unless absolutely necessary. Also fetch the dependent objects eagerly to avoid LazyInitializationException
  • 34. Quartz plugins { ... compile ":quartz:1.0.1" ... } //New commands grails create-job grails install-quartz-config grails create-job com.netflix.SupplierImport
  • 35.