Your SlideShare is downloading. ×
  • Like
Understanding GORM (Greach 2014)
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Now you can save presentations on your phone or tablet

Available for both IPhone and Android

Text the download link to your phone

Standard text messaging rates apply

Understanding GORM (Greach 2014)

  • 1,287 views
Published

GORM is one of the keys for the success of Grails, but for a Grails beginner some concepts may be a bit confusing. Even for a long time developer there can be some missconceptions due to the …

GORM is one of the keys for the success of Grails, but for a Grails beginner some concepts may be a bit confusing. Even for a long time developer there can be some missconceptions due to the abstractions layers of the framework.

In this talk I’ll try to cover some of the basics of GORM, Hibernate and how to interact with transactions and sessions. I’ll show some of the problems that I had starting with the Grails framework and how I think they are best solved.

Some other topics that I’ll go over are the interaction with GPars, and the differences between “session” and “transaction”.

Published in Software , Technology , Business
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
1,287
On SlideShare
0
From Embeds
0
Number of Embeds
4

Actions

Shares
Downloads
18
Comments
0
Likes
4

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. UNDERSTANDING GORM Alonso Torres @alotor http://goo.gl/U6sK5E
  • 2. Ego-slide Alonso Torres alotor @alotor Engineer atKaleidos
  • 3. GORM? Really? Is so easy, the easiestpartof Grails! Onlyafew POGO's to access the database Peachy!
  • 4. Some pitfalls The 'When did I modified thatobject?' defrenderBook(Stringisbn){ defbook=Book.findByIsbn(isbn) //Renderasuppercase book.title=book.title.toUpperCase() [book:book] }
  • 5. Some pitfalls The 'Rollback where are you?' defbuyBook(Stringuser,StringbookTitle,Longqty){ deffound=Book.findByTitle(bookTitle) //Saveaneworderfortheuser deforder=newBookOrder(user:user,book:found,quantity:qty) order.save() found.stock=found.stock-1 //Whennotfoundthrowexceptiontorollback if(found.stock<0){ thrownewException("Thisshouldrollback!") } returnfound }
  • 6. Some pitfalls The 'Parallelprocessing, It's easy!!' defprocessOrders(){ deforders=BookOrder.list() //Parallelupdateorders GParsPool.withPool(10){ orders.eachParallel{order-> dispatchingService.dispatch(order) order.sent=true order.save() } } }
  • 7. Some pitfalls The 'Failwhale' classUser{ Stringname statichasMany=[followers:User] } user.followers.isEmpty() CheckBurttalkabout"GORMPerformance"
  • 8. GORM is dark and full of terrors
  • 9. Let's take a step back... and start at the beginning
  • 10. Understanding Bootstrapping WHAT'S GOING ON BEHIND THE SCENES?
  • 11. Your first Domain class
  • 12. classBook{ Stringname Stringisbn Authorauthor }
  • 13. Grails Bootstrap Inspect/grails-app Classes inside /domain Annotates them with @grails.persistence.Entity grailsrun-app
  • 14. 1) Domain classes are found
  • 15. DEBUGcommons.DefaultGrailsApplication Inspecting[es.greach.gorm.Book] [es.greach.gorm.Book]isnotaFiltersclass. [es.greach.gorm.Book]isnotaCodecclass. [es.greach.gorm.Book]isnotaTagLibclass. [es.greach.gorm.Book]isnotaServiceclass. [es.greach.gorm.Book]isnotaControllerclass. [es.greach.gorm.Book]isnotaBootstrapclass. [es.greach.gorm.Book]isaDomainclass. Addingartefactclasses.greach.gorm.BookofkindDomain
  • 16. Grails initializes the Domain Class Prepares the relationship properties Resolves class hierarchy Add validation capabilities Integrates domain classes with Spring
  • 17. @grails.persistence.Entity Includes 'id'and 'version' Marks the classes as domain entities You can putdomain classes inside /src/main/groovy Manualyannotate them with @Entity
  • 18. @Entity classBook{ Longid Longversion Stringname Stringisbn Authorauthor }
  • 19. 2) GORM enhances classes
  • 20. classBook{ staticmapWith="mongo" Stringname Stringisbn }
  • 21. DEBUGcfg.HibernateUtils -EnhancingGORMentityBook
  • 22. GORM Enhancer Instances API (save, delete...) Classes API (findAll, where, withCriteria...) Dynamic Finders Validation (unique)
  • 23. GORM Enhancer Instances API (save, delete...) Classes API (findAll, where, withCriteria...) Dynamic Finders Validation (unique)
  • 24. Bootstraping DistinctGrails-base vs GORM @Entitycould potentialybe used outside Grails Problems with AST's Grails dependencies
  • 25. Understanding Spring HOW INTERACT DOMAIN CLASSES AND SPRING
  • 26. classBook{ defbookService Stringname Stringisbn Authorauthor StringtoString(){ returnbookService.parseBook(this) } } defmyBook=newBook() printlnmyBook.toString() [DEBUG]BookService::parseBook
  • 27. DI needs control on object instantiation Spring should create the object newBook()
  • 28. So Grails kind of "cheats"
  • 29. Spring Beans for a Domain Class BookValidator BookPersistentClass BookDomainClass Book
  • 30. newBook() Book.constructor={-> defctx=....//Springcontext context.getBean("Book") }
  • 31. What does that means? Springcreates your objects Be carefulwhen usingsome capabilities Example: SpringAOP
  • 32. Understanding Hibernate GORM WHERE THE DARKNESS LURKS
  • 33. GORM > Hibernate GORM provides abeautifulabstraction over hibernate Convention over configuration No more complicated XML or annotations Better collections
  • 34. But, Hibernate it's still there
  • 35. classBook{ Stringname Stringisbn Authorauthor } grailsgenerate-controllerBook //Grails2.2scafolding classBookController{ defsave(){ definstance=newBook(params) if(!instance.save(flush:true)){ render(view:"create",model:[bookInstance:instance]) return } redirect(action:"show",id:instance.id) } }
  • 36. //Grails2.2scafolding classBookController{ defsave(){ defbookInstance=newBook(params) if(!bookInstance.save(flush:true)){ render(view:"create",model:[bookInstance:bookInstance]) return } redirect(action:"show",id:bookInstance.id) } }
  • 37. OpenSessionInViewInterceptor Creates anew Sessionwithin aController scope Doesn'tcreate aTransaction So... there is NO transaction atthe controller After render the session is flushed
  • 38. Session? Transaction? I'm confused
  • 39. Session Entrypointto the Hibernate Framework In-Memorycache No thread safe and normalythread-bound
  • 40. GORM Entities Entities have arelationship with the session This defines a"life-cycle" Transient -notyetpersisted Persistent -has asession Detached -persisted butwithoutsession
  • 41. Session Flush Session checks "DIRTY OBJECTS" When flushed the changes are persisted to database
  • 42. After flush, are my objects in the DB? DEPENDS
  • 43. Transaction Database managed Provider specific Accessed through JDBC Driver
  • 44. PeterLedbrok- http://spring.io/blog/2010/06/23/gorm-gotchas-part-1/
  • 45. Hibernate Session FLUSHING vs COMMIT Database Transaction
  • 46. Automatic session flushing Queryexecuted Acontroller completes Before transaction commit
  • 47. Some pitfalls The 'When did I modified thatobject?' defrenderBook(Stringisbn){ defbook=Book.findByIsbn(isbn) //Renderasuppercase book.title=book.title.toUpperCase() [book:book] }
  • 48. Some pitfalls The 'When did I modified thatobject?' defrenderBook(Stringisbn){ defbook=Book.findByIsbn(isbn) //Deattachtheobjectfromthesession book.discard() //Renderasuppercase book.title=book.title.toUpperCase() [book:book] }
  • 49. Where do I put my transactional logic?
  • 50. withTransaction Book.withTransaction{ //Transactionalstuff }
  • 51. Transactional services @Transactional classBookService{ defdoTransactionalStuff(){ ... } }
  • 52. Be careful! Don'tinstanciate the services Don'tuse closures And... newTransactionalService().doTransactionalStuff() deftransactionalMethod={...}
  • 53. DON'T THROW CHECKED EXCEPTIONS
  • 54. Some pitfalls The 'Rollback where are you?' defbuyBook(Stringuser,StringbookTitle,Longqty){ deffound=Book.findByTitle(bookTitle) //Saveaneworderfortheuser deforder=newBookOrder(user:user,book:found,quantity:qty) order.save() found.stock=found.stock-1 //Whennotfoundthrowexceptiontorollback if(found.stock<0){ thrownewException("Thisshouldrollback!") } returnfound }
  • 55. Some pitfalls The 'Rollback where are you?' defbuyBook(Stringuser,StringbookTitle,Longqty){ deffound=Book.findByTitle(bookTitle) //Saveaneworderfortheuser deforder=newBookOrder(user:user,book:found,quantity:qty) order.save() found.stock=found.stock-1 //Whennotfoundthrowexceptiontorollback if(found.stock<0){ thrownewRuntimeException("Thisshouldrollback!") } returnfound }
  • 56. @Transactional vs @Transactional Spring@Transactionalcreates aPROXY Grails new @Transactionalis an AST
  • 57. Understanding Parallel GORM BRACE YOURSELVES
  • 58. Session is Thread-Local
  • 59. Some pitfalls The 'Concurrency, It's easy!!' defprocessOrders(){ deforders=BookOrder.list() //Parallelupdateorders GParsPool.withPool(10){ orders.eachParallel{order-> dispatchingService.dispatch(order) order.sent=true order.save() } } }
  • 60. Thread-local session Recovers alistof orders Each item is bound to the requestsession When we spawn the concurrentthreads the objects don't know where is their session deforders=Orders.findTodayOrders()
  • 61. Some pitfalls The 'Concurrency, It's easy!!' defprocessOrders(){ deforders=BookOrder.list() //Parallelupdateorders GParsPool.withPool(10){ orders.eachParallel{order-> BookOrder.withNewSession{ order.merge() dispatchingService.dispatch(order) order.sent=true order.save() } } } }
  • 62. Rule of thumb Session = Thread If entityhas recovered byanother thread Putitin the currentthread session
  • 63. Grails 2.3 Async GORM The new async GORM solves some problems Manages the session for the promise defpromise=Person.async.findByFirstName("Homer") defperson=promise.get()
  • 64. Grails 2.3 Async GORM Problem: Objecthas been retrieved byanother thread After the promise is resolved we have to attach the object defpromise=Person.async.findByFirstName("Homer") defperson=promise.get() person.merge()//Reboundtheobjecttothesession person.firstName="Bart"
  • 65. Closing thoughts GORM is averycoolabstraction You have to be aware of some of how things work With greatpower, comes greatresponsibility
  • 66. THANKS @alotor http://goo.gl/U6sK5E
  • 67. Bonus track (references) http://spring.io/blog/2010/06/23/gorm-gotchas-part-1/ http://sacharya.com/tag/gorm-transaction/ http://www.anyware.co.uk/2005/2012/11/12/the-false- optimism-of-gorm-and-hibernate/ http://docs.jboss.org/hibernate/orm/3.6/reference/en- US/html_single/#transactions-basics
  • 68. Bonus track (references) http://www.infoq.com/presentations/GORM-Performance http://www.infoq.com/presentations/grails-transaction http://blog.octo.com/en/transactions-in-grails/ https://community.jboss.org/wiki/OpenSessioninView