Download - Understanding GORM (Greach 2014)

Transcript
Page 1: Understanding GORM (Greach 2014)

UNDERSTANDING GORM

Alonso Torres @alotorhttp://goo.gl/U6sK5E

Page 2: Understanding GORM (Greach 2014)

Ego-slideAlonso Torres

alotor @alotor

Engineer at Kaleidos

Page 3: Understanding GORM (Greach 2014)

GORM? Really?Is so easy, the easiest part of Grails!

Only a few POGO's to access the database

Peachy!

Page 4: Understanding GORM (Greach 2014)
Page 5: Understanding GORM (Greach 2014)

Some pitfallsThe 'When did I modified that object?'

def renderBook(String isbn) { def book = Book.findByIsbn(isbn)

// Render as uppercase book.title = book.title.toUpperCase()

[book: book]}

Page 6: Understanding GORM (Greach 2014)

Some pitfallsThe 'Rollback where are you?'

def buyBook(String user, String bookTitle, Long qty) { def found = Book.findByTitle(bookTitle)

// Save a new order for the user def order = new BookOrder(user:user, book:found, quantity: qty) order.save()

found.stock = found.stock - 1

// When not found throw exception to rollback if (found.stock < 0) { throw new Exception("This should rollback!") } return found}

Page 7: Understanding GORM (Greach 2014)

Some pitfallsThe 'Parallel processing, It's easy!!'

def processOrders() { def orders = BookOrder.list()

// Parallel update orders GParsPool.withPool(10) { orders.eachParallel { order -> dispatchingService.dispatch(order) order.sent = true order.save() } }}

Page 8: Understanding GORM (Greach 2014)

Some pitfallsThe 'Fail whale'

class User { String name static hasMany = [followers:User]}

user.followers.isEmpty()

Check Burt talk about "GORM Performance"

Page 9: Understanding GORM (Greach 2014)

GORM is dark and full ofterrors

Page 10: Understanding GORM (Greach 2014)

Let's take a step back...and start at the beginning

Page 11: Understanding GORM (Greach 2014)

Understanding BootstrappingWHAT'S GOING ON BEHIND THE SCENES?

Page 12: Understanding GORM (Greach 2014)

Your first Domain class

Page 13: Understanding GORM (Greach 2014)

class Book { String name String isbn Author author}

Page 14: Understanding GORM (Greach 2014)

Grails Bootstrap

Inspect /grails-app

Classes inside /domain

Annotates them with @grails.persistence.Entity

grails run-app

Page 15: Understanding GORM (Greach 2014)

1) Domain classes are found

Page 16: Understanding GORM (Greach 2014)

DEBUG commons.DefaultGrailsApplicationInspecting [es.greach.gorm.Book][es.greach.gorm.Book] is not a Filters class.[es.greach.gorm.Book] is not a Codec class.[es.greach.gorm.Book] is not a TagLib class.[es.greach.gorm.Book] is not a Service class.[es.greach.gorm.Book] is not a Controller class.[es.greach.gorm.Book] is not a Bootstrap class.[es.greach.gorm.Book] is a Domain class.Adding artefact class es.greach.gorm.Book of kind Domain

Page 17: Understanding GORM (Greach 2014)

Grails initializes the Domain ClassPrepares the relationship properties

Resolves class hierarchy

Add validation capabilities

Integrates domain classes with Spring

Page 18: Understanding GORM (Greach 2014)

@grails.persistence.EntityIncludes 'id' and 'version'

Marks the classes as domain entities

You can put domain classes inside /src/main/groovy

Manualy annotate them with @Entity

Page 19: Understanding GORM (Greach 2014)

@Entityclass Book { Long id Long version

String name String isbn Author author}

Page 20: Understanding GORM (Greach 2014)

2) GORM enhances classes

Page 21: Understanding GORM (Greach 2014)

class Book { static mapWith = "mongo"

String name String isbn}

Page 22: Understanding GORM (Greach 2014)

DEBUG cfg.HibernateUtils - Enhancing GORM entity Book

Page 23: Understanding GORM (Greach 2014)

GORM EnhancerInstances API (save, delete...)

Classes API (findAll, where, withCriteria...)

Dynamic Finders

Validation (unique)

Page 24: Understanding GORM (Greach 2014)

GORM EnhancerInstances API (save, delete...)

Classes API (findAll, where, withCriteria...)

Dynamic Finders

Validation (unique)

Page 25: Understanding GORM (Greach 2014)

BootstrapingDistinct Grails-base vs GORM

@Entity could potentialy be used outside GrailsProblems with AST's

Grails dependencies

Page 26: Understanding GORM (Greach 2014)

Understanding SpringHOW INTERACT DOMAIN CLASSES AND SPRING

Page 27: Understanding GORM (Greach 2014)

class Book { def bookService

String name String isbn Author author

String toString() { return bookService.parseBook(this) }}

def myBook = new Book()println myBook.toString()

[DEBUG] BookService::parseBook

Page 28: Understanding GORM (Greach 2014)

DI needs control on object instantiation

Spring should create the objectnew Book()

Page 29: Understanding GORM (Greach 2014)

So Grails kind of "cheats"

Page 30: Understanding GORM (Greach 2014)

Spring Beans for a Domain ClassBookValidator

BookPersistentClass

BookDomainClass

Book

Page 31: Understanding GORM (Greach 2014)

new Book()

Book.constructor = {-> def ctx = .... // Spring context context.getBean("Book")}

Page 32: Understanding GORM (Greach 2014)

What does that means?Spring creates your objects

Be careful when using some capabilities

Example: Spring AOP

Page 33: Understanding GORM (Greach 2014)

Understanding Hibernate GORMWHERE THE DARKNESS LURKS

Page 34: Understanding GORM (Greach 2014)

GORM > HibernateGORM provides a beautiful abstraction over hibernate

Convention over configuration

No more complicated XML or annotations

Better collections

Page 35: Understanding GORM (Greach 2014)

But, Hibernate it's still there

Page 36: Understanding GORM (Greach 2014)

class Book { String name String isbn Author author}

grails generate-controller Book

// Grails 2.2 scafoldingclass BookController { def save() { def instance = new Book(params) if (!instance.save(flush: true)) { render(view: "create", model: [bookInstance: instance]) return } redirect(action: "show", id: instance.id) }}

Page 37: Understanding GORM (Greach 2014)
Page 38: Understanding GORM (Greach 2014)

// Grails 2.2 scafoldingclass BookController { def save() { def bookInstance = new Book(params) if (!bookInstance.save(flush: true)) { render(view: "create", model: [bookInstance: bookInstance]) return } redirect(action: "show", id: bookInstance.id) }}

Page 39: Understanding GORM (Greach 2014)

OpenSessionInViewInterceptorCreates a new Session within a Controller scope

Doesn't create a Transaction

So... there is NO transaction at the controller

After render the session is flushed

Page 40: Understanding GORM (Greach 2014)

Session? Transaction? I'm confused

Page 41: Understanding GORM (Greach 2014)

SessionEntry point to the Hibernate Framework

In-Memory cache

No thread safe and normaly thread-bound

Page 42: Understanding GORM (Greach 2014)

GORM EntitiesEntities have a relationship with the session

This defines a "life-cycle"

Transient - not yet persisted

Persistent - has a session

Detached - persisted but without session

Page 43: Understanding GORM (Greach 2014)
Page 44: Understanding GORM (Greach 2014)

Session FlushSession checks "DIRTY OBJECTS"

When flushed the changes are persisted to database

Page 45: Understanding GORM (Greach 2014)

After flush, are my objects in the DB?

DEPENDS

Page 46: Understanding GORM (Greach 2014)

TransactionDatabase managed

Provider specific

Accessed through JDBC Driver

Page 47: Understanding GORM (Greach 2014)

Peter Ledbrok - http://spring.io/blog/2010/06/23/gorm-gotchas-part-1/

Page 48: Understanding GORM (Greach 2014)

Hibernate SessionFLUSHING

vsCOMMIT

Database Transaction

Page 49: Understanding GORM (Greach 2014)

Automatic session flushingQuery executed

A controller completes

Before transaction commit

Page 50: Understanding GORM (Greach 2014)

Some pitfallsThe 'When did I modified that object?'

def renderBook(String isbn) { def book = Book.findByIsbn(isbn)

// Render as uppercase book.title = book.title.toUpperCase()

[book: book]}

Page 51: Understanding GORM (Greach 2014)

Some pitfallsThe 'When did I modified that object?'

def renderBook(String isbn) { def book = Book.findByIsbn(isbn)

// Deattach the object from the session book.discard()

// Render as uppercase book.title = book.title.toUpperCase()

[book: book]}

Page 52: Understanding GORM (Greach 2014)

Where do I put my transactional logic?

Page 53: Understanding GORM (Greach 2014)

withTransactionBook.withTransaction { // Transactional stuff}

Page 54: Understanding GORM (Greach 2014)

Transactional services@Transactionalclass BookService { def doTransactionalStuff(){ ... }}

Page 55: Understanding GORM (Greach 2014)
Page 56: Understanding GORM (Greach 2014)

Be careful!Don't instanciate the services

Don't use closures

And...

new TransactionalService().doTransactionalStuff()

def transactionalMethod = { ... }

Page 57: Understanding GORM (Greach 2014)

DON'T THROW CHECKED EXCEPTIONS

Page 58: Understanding GORM (Greach 2014)

Some pitfallsThe 'Rollback where are you?'

def buyBook(String user, String bookTitle, Long qty) { def found = Book.findByTitle(bookTitle)

// Save a new order for the user def order = new BookOrder(user:user, book:found, quantity: qty) order.save()

found.stock = found.stock - 1

// When not found throw exception to rollback if (found.stock < 0) { throw new Exception("This should rollback!") } return found}

Page 59: Understanding GORM (Greach 2014)

Some pitfallsThe 'Rollback where are you?'

def buyBook(String user, String bookTitle, Long qty) { def found = Book.findByTitle(bookTitle)

// Save a new order for the user def order = new BookOrder(user:user, book:found, quantity: qty) order.save()

found.stock = found.stock - 1

// When not found throw exception to rollback if (found.stock < 0) { throw new RuntimeException("This should rollback!") } return found}

Page 60: Understanding GORM (Greach 2014)

@Transactional vs @TransactionalSpring @Transactional creates a PROXY

Grails new @Transactional is an AST

Page 61: Understanding GORM (Greach 2014)

Understanding Parallel GORMBRACE YOURSELVES

Page 62: Understanding GORM (Greach 2014)

Session is Thread-Local

Page 63: Understanding GORM (Greach 2014)

Some pitfallsThe 'Concurrency, It's easy!!'

def processOrders() { def orders = BookOrder.list()

// Parallel update orders GParsPool.withPool(10) { orders.eachParallel { order -> dispatchingService.dispatch(order) order.sent = true order.save() } }}

Page 64: Understanding GORM (Greach 2014)

Thread-local sessionRecovers a list of orders

Each item is bound to the request session

When we spawn the concurrent threads the objects don'tknow where is their session

def orders = Orders.findTodayOrders()

Page 65: Understanding GORM (Greach 2014)

Some pitfallsThe 'Concurrency, It's easy!!'

def processOrders() { def orders = BookOrder.list()

// Parallel update orders GParsPool.withPool(10) { orders.eachParallel { order -> BookOrder.withNewSession { order.merge()

dispatchingService.dispatch(order) order.sent = true order.save() } } }}

Page 66: Understanding GORM (Greach 2014)

Rule of thumbSession = Thread

If entity has recovered by another thread

Put it in the current thread session

Page 67: Understanding GORM (Greach 2014)

Grails 2.3 Async GORMThe new async GORM solves some problems

Manages the session for the promise

def promise = Person.async.findByFirstName("Homer")def person = promise.get()

Page 68: Understanding GORM (Greach 2014)

Grails 2.3 Async GORMProblem: Object has been retrieved by another thread

After the promise is resolved we have to attach the object

def promise = Person.async.findByFirstName("Homer")def person = promise.get()person.merge() // Rebound the object to the sessionperson.firstName = "Bart"

Page 69: Understanding GORM (Greach 2014)
Page 70: Understanding GORM (Greach 2014)

Closing thoughtsGORM is a very cool abstraction

You have to be aware of some of how things work

With great power, comes great responsibility

Page 71: Understanding GORM (Greach 2014)

THANKS

@alotor

http://goo.gl/U6sK5E

Page 72: Understanding GORM (Greach 2014)

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

Page 73: Understanding GORM (Greach 2014)

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