SlideShare une entreprise Scribd logo
1  sur  37
Télécharger pour lire hors ligne
Advanced GORM -
Performance, Customization
and Monitoring
Burt Beckwith
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
Overview
• Demonstration of potential performance issues
with mapped collections in GORM
• Using the Hibernate 2nd
-level cache
• Monitoring and managing 2nd
-level caches
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
Standard Grails One-to-Many
Library has many Visits:
class Library {
String name
static hasMany = [visits: Visit]
}
class Visit {
String personName
Date visitDate = new Date()
static belongsTo = [library: Library]
}
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
Standard Grails One-to-Many
Usage:
• object-oriented way to record visits to a library
• convenience methods
addToVisits()/removeFromVisits() handle
add/remove and cascading save/delete
Library library = new Library(name: 'Carnegie').save()
...
library.addToVisits(new Visit(personName:'me'))
library.save()
...
library.addToVisits(new Visit(personName:'me2'))
library.save()
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
Standard Grails One-to-Many
DDL (use grails schema-export to generate):
create table library (
id bigint generated by default as identity (start with 1),
version bigint not null,
name varchar(255) not null,
primary key (id)
);
create table visit (
id bigint generated by default as identity (start with 1),
version bigint not null,
library_id bigint not null,
person_name varchar(255) not null,
visit_date timestamp not null,
primary key (id)
);
alter table visit add constraint FK6B04D4B4AEC8BBA
foreign key (library_id) references library;
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
So What's the Problem?
• “hasMany = [visits: Visit]” creates a Set
(org.hibernate.collection.PersistentSet) in Library – the
“inverse” collection in traditional Hibernate
• Adding to the Set requires loading all instances from the
database to guarantee uniqueness, even if you know the
new item is unique
• Likewise for a mapped List – Hibernate pulls the entire
collection to maintain the correct order, even if you're
adding to the end of the list
• In traditional Hibernate you could map the collection as a
Bag, which is just a regular Collection with no ordering or
uniqueness guarantees, but Grails doesn't support Bags
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
So What's the Problem?
• You get a false sense of security since it's a lazy-
loaded collection (by default); loading a Library
doesn't load all Visits, but that's only partially
helpful
• Works fine in development when you only have
a few Visits, but imagine when you deploy to
production and you have 1,000,000 Visits and
want to add one more
• Risk of artificial optimistic locking exceptions;
altering a mapped collection bumps the version,
so simultaneous Visit creations can break but
shouldn't
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
Demo
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
Ok, So What's the Solution?
Remove the collection:
class Library {
String name
}
class Visit {
String personName
Date visitDate = new Date()
Library library
}
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
How does that affect usage?
• Different syntax for persisting a Visit
• No cascading; to delete a Library you need to
delete its Visits first (in a transactional service
method!)
Library library = new Library(name: 'Carnegie').save()
...
new Visit(personName:'me', library: library).save()
...
new Visit(personName:'me2', library: library).save()
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
How does that affect usage?
• If you want to know all Visits for a Library, use a
custom finder:
• This is actually significantly more convenient
since you can query for the 10 most recent, just
last month's visits, etc.
def visits = Visit.findAllByLibrary(library)
def last10 = Visit.executeQuery(
"from Visit v where v.library=:library " +
"order by v.visitDate desc", [library: library],
[max: 10])
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
How does this affect DDL?
Not at all, both approaches set visit.library_id:
create table library (
id bigint generated by default as identity (start with 1),
version bigint not null,
name varchar(255) not null,
primary key (id)
);
create table visit (
id bigint generated by default as identity (start with 1),
version bigint not null,
library_id bigint not null,
person_name varchar(255) not null,
visit_date timestamp not null,
primary key (id)
);
alter table visit add constraint FK6B04D4B4AEC8BBA
foreign key (library_id) references library;
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
Standard Grails Many-to-Many
User has many Roles, Role has many Users:
class User {
static hasMany = [roles: Role]
String username
}
class Role {
static belongsTo = User
static hasMany = [users: User]
String name
}
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
Standard Grails Many-to-Many
Usage:
Role roleUser = new Role(name: 'ROLE_USER').save()
Role roleAdmin = new Role(name: 'ROLE_ADMIN').save()
…
User user1 = new User(username:'user1')
user1.addToRoles(roleUser)
user1.save()
...
User user2 = new User(username:'user2')
user2.addToRoles(roleAdmin)
user2.save()
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
Standard Grails Many-to-Many
• Object-oriented approach to assigning a Role to
a User
• Syntax is very similar to One-to-many
• Convenience methods addToRoles() and
removeFromRoles() handle adding to/removing
from mapped collection and cascading
save/delete
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
Standard Grails Many-to-Many
DDL (use grails schema-export to generate):
create table role (
id bigint generated by default as identity (start with 1),
version bigint not null,
name varchar(255) not null,
primary key (id)
);
create table user (
id bigint generated by default as identity (start with 1),
version bigint not null,
username varchar(255) not null,
primary key (id)
);
create table user_roles (
user_id bigint not null,
role_id bigint not null,
primary key (user_id, role_id)
);
alter table user_roles add constraint FK7342994952388A1A foreign key (role_id) references role;
alter table user_roles add constraint FK73429949F7634DFA foreign key (user_id) references user;
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
So What's the Problem?
• "hasMany = [users: User]" and "hasMany = [roles: Role]"
create a Set (org.hibernate.collection.PersistentSet) in
both User and Role
• Adding a Role to a User's 'roles' Set requires loading all
instances of the User's Roles (for uniqueness check) AND
all other Users who already have that Role from the
database
• This is because Grails automatically maps both collections
for you and populates both - "user.addToRoles(role)" and
"role.addToUsers(user)" are equivalent because it's
bidirectional
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
So What's the Problem?
• Works fine in development when you only have a few
Users, but imagine when you deploy to production and
you have 1,000,000 registered site users with
ROLE_MEMBER and want to add one more
• Risk of artificial optimistic locking exceptions; altering a
mapped collection bumps the version, so simultaneous
Role grants can break but shouldn't
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
Demo
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
Ok, So What's the Solution?
Remove the collections and map the join table:
class User {
String username
}
class Role {
String name
}
class UserRole implements Serializable {
User user
Role role
static mapping = {
table 'user_roles'
version false
id composite: ['user', 'role']
}
}
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
Ok, So What's the Solution?
We can add some helper methods to UserRole:
class UserRole implements Serializable {
...
static UserRole create(User user, Role role, boolean flush = false) {
UserRole userRole = new UserRole(user: user, role: role)
userRole.save(flush: flush, insert: true)
return userRole
}
static boolean remove(User user, Role role, boolean flush = false) {
UserRole userRole = UserRole.findByUserAndRole(user, role)
return userRole ? userRole.delete(flush: flush) : false
}
static void removeAll(User user) {
executeUpdate("DELETE FROM UserRole WHERE user=:user", [user: user])
}
}
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
Ok, So What's the Solution?
and restore a 'roles' pseudo-collection back in User:
class User {
String username
Set<Role> getRoles() {
UserRole.findAllByUser(this).collect { it.role } as Set
}
boolean hasRole(Role role) {
UserRole.countByUserAndRole(this, role) > 0
}
}
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
How does that affect usage?
• Different syntax for granting a Role
• No cascading; to delete a User you you need to
delete (disassociate) its Roles first (use
UserRole.removeAll(User user))
User user = …
Role role = …
UserRole.create user, role
– or –
UserRole.remove user, role
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
So Never Use Mapped Collections?
• No, you need to examine each case
• The standard approach is fine if the collections
are reasonably small – both sides in the case of
Many-to-Many
• The collections will contain proxies, so they're
smaller than real instances until initialized, but
still a memory concern
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
Using Hibernate 2nd
-Level Cache
DataSource.groovy:
dataSource {
pooled = true
driverClassName = 'com.mysql.jdbc.Driver'
url = ...
username = ...
password = ...
dialect = org.hibernate.dialect.MySQL5InnoDBDialect
}
hibernate {
cache.use_second_level_cache = true
cache.use_query_cache = true
cache.provider_class = 'org.hibernate.cache.EhCacheProvider'
}
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
Mapping in Domain Classes
class Book {
…
static mapping = { cache true }
}
class Country {
…
static mapping = { cache usage: 'read-only' }
}
class Author {
…
static hasMany = [books:Book]
static mapping = { books cache: true }
}
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
Usage Notes
• The 1st
-level cache is the Hibernate Session
• Can significantly reduce database load by keeping
instances in memory
• Can be distributed between multiple servers to let one
instance load from the database and share updated
instances, avoiding extra database trips
• "cache true" creates a read-write cache, best for read-
mostly objects since frequently-updated objects will result
in excessive cache invalidation (and network traffic when
distributed)
• "cache usage: 'read-only'" creates a read-only cache, best
for lookup data (e.g. Countries, States, Zip Codes, Roles,
etc.) that never change
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
Usage Notes
• DomainClass.get() always uses the 2nd-level cache
• By default nothing else always uses the cache but can be
overridden
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
Configuring with ehcache.xml
• If you don't create an ehcache.xml file in the classpath
(either grails-app/conf or src/java) EhCache will use built-
in defaults and you'll see warnings at startup
<ehcache>
<diskStore path="java.io.tmpdir" />
<defaultCache
maxElementsInMemory="10000"
eternal="false"
...
/>
<cache name="com.foo.bar.Thing"
maxElementsInMemory="10000"
eternal="false" overflowToDisk="false"
maxElementsOnDisk="0"
/>
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
Configuring with ehcache.xml
<cache name="com.foo.bar.Zipcode"
maxElementsInMemory="100000"
eternal="true" overflowToDisk="false"
maxElementsOnDisk="0"
/>
<cache name="org.hibernate.cache.StandardQueryCache"
maxElementsInMemory="50"
eternal="false" overflowToDisk="false"
maxElementsOnDisk="0"
timeToLiveSeconds="120"
/>
<!-- timestamps of the most recent updates to queryable tables -->
<cache name="org.hibernate.cache.UpdateTimestampsCache"
maxElementsInMemory="5000"
eternal="true" overflowToDisk="false"
maxElementsOnDisk="0"
/>
</ehcache>
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
Query Cache
• Criteria queries:
• HQL queries:
• In dynamic finders (new in 1.1)
def criteria = DomainClass.createCriteria()
def results = criteria.list {
cacheable(true)
}
DomainClass.withSession { session ->
return session.createQuery(
"select ... from … where ...")
.setCacheable(true).list()
}
}
def person = Person.findByFirstName("Fred", [cache:true])
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
Hibernate query cache
considered harmful?
• Most queries are not good candidates for
caching; must be same query and same
parameters
• Updates to domain classes will pessimistically
flush all potentially affected cached results
• DomainClass.list() is a decent candidate if there
aren't any (or many) updates and the total
number isn't huge
• Great blog post by Alex Miller (of Terracotta)
http://tech.puredanger.com/2009/07/10/hibern
ate-query-cache/
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
2nd
-Level Cache API
• evict one instance
– sessionFactory.evict(DomainClass, id)
• evict all instances
– sessionFactory.evict(DomainClass)
• evict one instance's collection
– sessionFactory.evictCollection(
'DomainClass.collectionName', id)
• evict all collections of DomainClass
– sessionFactory.evictCollection(
'DomainClass.collectionName')
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
2nd
-Level Cache API
• sessionFactory.statistics
(org.hibernate.stat.Statistics) methods:
– statistics.queryCacheHitCount
– statistics.queryCacheMissCount
– statistics.queryCachePutCount
– statistics.secondLevelCacheHitCount
– statistics.secondLevelCacheMissCount
– statistics.secondLevelCachePutCount
– statistics.secondLevelCacheRegionNames
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
2nd
-Level Cache API
• statistics.getSecondLevelCacheStatistics(cacheName)
(org.hibernate.stat.SecondLevelCacheStatistics)
methods:
– cacheStatistics.elementCountInMemory
– cacheStatistics.elementCountOnDisk
– cacheStatistics.hitCount
– cacheStatistics.missCount
– cacheStatistics.putCount
– cacheStatistics.sizeInMemory
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
Monitoring Demo
SpringOne 2GX 2009. All rights reserved. Do not distribute without permission.
Q&A

Contenu connexe

Tendances

Ad hoc Polymorphism using Type Classes and Cats
Ad hoc Polymorphism using Type Classes and CatsAd hoc Polymorphism using Type Classes and Cats
Ad hoc Polymorphism using Type Classes and CatsPhilip Schwarz
 
Exploring ZIO Prelude: The game changer for typeclasses in Scala
Exploring ZIO Prelude: The game changer for typeclasses in ScalaExploring ZIO Prelude: The game changer for typeclasses in Scala
Exploring ZIO Prelude: The game changer for typeclasses in ScalaJorge Vásquez
 
10 things, an Oracle DBA should care about when moving to PostgreSQL
10 things, an Oracle DBA should care about when moving to PostgreSQL10 things, an Oracle DBA should care about when moving to PostgreSQL
10 things, an Oracle DBA should care about when moving to PostgreSQLPostgreSQL-Consulting
 
Managing Social Content with MongoDB
Managing Social Content with MongoDBManaging Social Content with MongoDB
Managing Social Content with MongoDBMongoDB
 
React + Redux + TypeScript === ♥
React + Redux + TypeScript === ♥React + Redux + TypeScript === ♥
React + Redux + TypeScript === ♥Remo Jansen
 
How to remove disable an oa framework personalization (doc id 304670
How to remove  disable an oa framework personalization (doc id 304670How to remove  disable an oa framework personalization (doc id 304670
How to remove disable an oa framework personalization (doc id 304670Ahmad Mkade
 
How to efficiently handle period-close process in Oracle EBS R12.pdf
How to efficiently handle period-close process in Oracle EBS R12.pdfHow to efficiently handle period-close process in Oracle EBS R12.pdf
How to efficiently handle period-close process in Oracle EBS R12.pdfSridhar
 
MySQL Parallel Replication (LOGICAL_CLOCK): all the 5.7 (and some of the 8.0)...
MySQL Parallel Replication (LOGICAL_CLOCK): all the 5.7 (and some of the 8.0)...MySQL Parallel Replication (LOGICAL_CLOCK): all the 5.7 (and some of the 8.0)...
MySQL Parallel Replication (LOGICAL_CLOCK): all the 5.7 (and some of the 8.0)...Jean-François Gagné
 
Django admin site 커스텀하여 적극적으로 활용하기
Django admin site 커스텀하여 적극적으로 활용하기Django admin site 커스텀하여 적극적으로 활용하기
Django admin site 커스텀하여 적극적으로 활용하기영우 박
 
What's new in Oracle 19c & 18c Recovery Manager (RMAN)
What's new in Oracle 19c & 18c Recovery Manager (RMAN)What's new in Oracle 19c & 18c Recovery Manager (RMAN)
What's new in Oracle 19c & 18c Recovery Manager (RMAN)Satishbabu Gunukula
 
Dynamically Generate a CRUD Admin Panel with Java Annotations
Dynamically Generate a CRUD Admin Panel with Java AnnotationsDynamically Generate a CRUD Admin Panel with Java Annotations
Dynamically Generate a CRUD Admin Panel with Java AnnotationsBroadleaf Commerce
 
Algebraic Data Types for Data Oriented Programming - From Haskell and Scala t...
Algebraic Data Types forData Oriented Programming - From Haskell and Scala t...Algebraic Data Types forData Oriented Programming - From Haskell and Scala t...
Algebraic Data Types for Data Oriented Programming - From Haskell and Scala t...Philip Schwarz
 

Tendances (20)

Modern JS with ES6
Modern JS with ES6Modern JS with ES6
Modern JS with ES6
 
Ad hoc Polymorphism using Type Classes and Cats
Ad hoc Polymorphism using Type Classes and CatsAd hoc Polymorphism using Type Classes and Cats
Ad hoc Polymorphism using Type Classes and Cats
 
Exploring ZIO Prelude: The game changer for typeclasses in Scala
Exploring ZIO Prelude: The game changer for typeclasses in ScalaExploring ZIO Prelude: The game changer for typeclasses in Scala
Exploring ZIO Prelude: The game changer for typeclasses in Scala
 
ZIO Queue
ZIO QueueZIO Queue
ZIO Queue
 
Customizing Oracle EBS OA Framework
Customizing Oracle EBS OA FrameworkCustomizing Oracle EBS OA Framework
Customizing Oracle EBS OA Framework
 
10 things, an Oracle DBA should care about when moving to PostgreSQL
10 things, an Oracle DBA should care about when moving to PostgreSQL10 things, an Oracle DBA should care about when moving to PostgreSQL
10 things, an Oracle DBA should care about when moving to PostgreSQL
 
Managing Social Content with MongoDB
Managing Social Content with MongoDBManaging Social Content with MongoDB
Managing Social Content with MongoDB
 
Callback Function
Callback FunctionCallback Function
Callback Function
 
React + Redux + TypeScript === ♥
React + Redux + TypeScript === ♥React + Redux + TypeScript === ♥
React + Redux + TypeScript === ♥
 
How to remove disable an oa framework personalization (doc id 304670
How to remove  disable an oa framework personalization (doc id 304670How to remove  disable an oa framework personalization (doc id 304670
How to remove disable an oa framework personalization (doc id 304670
 
How to efficiently handle period-close process in Oracle EBS R12.pdf
How to efficiently handle period-close process in Oracle EBS R12.pdfHow to efficiently handle period-close process in Oracle EBS R12.pdf
How to efficiently handle period-close process in Oracle EBS R12.pdf
 
MySQL Parallel Replication (LOGICAL_CLOCK): all the 5.7 (and some of the 8.0)...
MySQL Parallel Replication (LOGICAL_CLOCK): all the 5.7 (and some of the 8.0)...MySQL Parallel Replication (LOGICAL_CLOCK): all the 5.7 (and some of the 8.0)...
MySQL Parallel Replication (LOGICAL_CLOCK): all the 5.7 (and some of the 8.0)...
 
Django admin site 커스텀하여 적극적으로 활용하기
Django admin site 커스텀하여 적극적으로 활용하기Django admin site 커스텀하여 적극적으로 활용하기
Django admin site 커스텀하여 적극적으로 활용하기
 
Manual Activos Fijos en ORACLE EBS
Manual Activos Fijos en ORACLE EBSManual Activos Fijos en ORACLE EBS
Manual Activos Fijos en ORACLE EBS
 
What's new in Oracle 19c & 18c Recovery Manager (RMAN)
What's new in Oracle 19c & 18c Recovery Manager (RMAN)What's new in Oracle 19c & 18c Recovery Manager (RMAN)
What's new in Oracle 19c & 18c Recovery Manager (RMAN)
 
Dynamically Generate a CRUD Admin Panel with Java Annotations
Dynamically Generate a CRUD Admin Panel with Java AnnotationsDynamically Generate a CRUD Admin Panel with Java Annotations
Dynamically Generate a CRUD Admin Panel with Java Annotations
 
Algebraic Data Types for Data Oriented Programming - From Haskell and Scala t...
Algebraic Data Types forData Oriented Programming - From Haskell and Scala t...Algebraic Data Types forData Oriented Programming - From Haskell and Scala t...
Algebraic Data Types for Data Oriented Programming - From Haskell and Scala t...
 
Less10 undo
Less10 undoLess10 undo
Less10 undo
 
Java server pages
Java server pagesJava server pages
Java server pages
 
Meta Programming in Groovy
Meta Programming in GroovyMeta Programming in Groovy
Meta Programming in Groovy
 

En vedette

Performance tuning Grails applications
Performance tuning Grails applicationsPerformance tuning Grails applications
Performance tuning Grails applicationsLari Hotari
 
Hacking the Grails Spring Security 2.0 Plugin
Hacking the Grails Spring Security 2.0 PluginHacking the Grails Spring Security 2.0 Plugin
Hacking the Grails Spring Security 2.0 PluginBurt Beckwith
 
Fun With Spring Security
Fun With Spring SecurityFun With Spring Security
Fun With Spring SecurityBurt Beckwith
 
Think beyond frameworks, The real gems are in the languages
Think beyond frameworks, The real gems are in the languagesThink beyond frameworks, The real gems are in the languages
Think beyond frameworks, The real gems are in the languagesNaresha K
 
GR8Conf 2011: Tuning Grails Applications by Peter Ledbrook
GR8Conf 2011: Tuning Grails Applications by Peter LedbrookGR8Conf 2011: Tuning Grails Applications by Peter Ledbrook
GR8Conf 2011: Tuning Grails Applications by Peter LedbrookGR8Conf
 
Grails Worst Practices
Grails Worst PracticesGrails Worst Practices
Grails Worst PracticesBurt Beckwith
 
Hacking the Grails Spring Security Plugins
Hacking the Grails Spring Security PluginsHacking the Grails Spring Security Plugins
Hacking the Grails Spring Security PluginsGR8Conf
 
Little Did He Know ...
Little Did He Know ...Little Did He Know ...
Little Did He Know ...Burt Beckwith
 
Geb+spock: let your functional tests live long and prosper
Geb+spock: let your functional tests live long and prosperGeb+spock: let your functional tests live long and prosper
Geb+spock: let your functional tests live long and prosperEsther Lozano
 
GriffDnie (Griffon Demo)
GriffDnie (Griffon Demo)GriffDnie (Griffon Demo)
GriffDnie (Griffon Demo)Jorge Aguilera
 
Macro macro, burrito burrit
Macro macro, burrito burritMacro macro, burrito burrit
Macro macro, burrito burritMario García
 

En vedette (12)

Performance tuning Grails applications
Performance tuning Grails applicationsPerformance tuning Grails applications
Performance tuning Grails applications
 
Hacking the Grails Spring Security 2.0 Plugin
Hacking the Grails Spring Security 2.0 PluginHacking the Grails Spring Security 2.0 Plugin
Hacking the Grails Spring Security 2.0 Plugin
 
Fun With Spring Security
Fun With Spring SecurityFun With Spring Security
Fun With Spring Security
 
Think beyond frameworks, The real gems are in the languages
Think beyond frameworks, The real gems are in the languagesThink beyond frameworks, The real gems are in the languages
Think beyond frameworks, The real gems are in the languages
 
GR8Conf 2011: Tuning Grails Applications by Peter Ledbrook
GR8Conf 2011: Tuning Grails Applications by Peter LedbrookGR8Conf 2011: Tuning Grails Applications by Peter Ledbrook
GR8Conf 2011: Tuning Grails Applications by Peter Ledbrook
 
Grails Worst Practices
Grails Worst PracticesGrails Worst Practices
Grails Worst Practices
 
Hacking the Grails Spring Security Plugins
Hacking the Grails Spring Security PluginsHacking the Grails Spring Security Plugins
Hacking the Grails Spring Security Plugins
 
Little Did He Know ...
Little Did He Know ...Little Did He Know ...
Little Did He Know ...
 
Geb+spock: let your functional tests live long and prosper
Geb+spock: let your functional tests live long and prosperGeb+spock: let your functional tests live long and prosper
Geb+spock: let your functional tests live long and prosper
 
De Java a Swift pasando por Groovy
De Java a Swift pasando por GroovyDe Java a Swift pasando por Groovy
De Java a Swift pasando por Groovy
 
GriffDnie (Griffon Demo)
GriffDnie (Griffon Demo)GriffDnie (Griffon Demo)
GriffDnie (Griffon Demo)
 
Macro macro, burrito burrit
Macro macro, burrito burritMacro macro, burrito burrit
Macro macro, burrito burrit
 

Similaire à Advanced GORM - Performance, Customization and Monitoring

jQuery in the [Aol.] Enterprise
jQuery in the [Aol.] EnterprisejQuery in the [Aol.] Enterprise
jQuery in the [Aol.] EnterpriseDave Artz
 
Clojure and Modularity
Clojure and ModularityClojure and Modularity
Clojure and Modularityelliando dias
 
REST APIs in Laravel 101
REST APIs in Laravel 101REST APIs in Laravel 101
REST APIs in Laravel 101Samantha Geitz
 
Oscon Java Testing on the Fast Lane
Oscon Java Testing on the Fast LaneOscon Java Testing on the Fast Lane
Oscon Java Testing on the Fast LaneAndres Almiray
 
Converting your JS library to a jQuery plugin
Converting your JS library to a jQuery pluginConverting your JS library to a jQuery plugin
Converting your JS library to a jQuery pluginthehoagie
 
Venturing Into The Wild: A .NET Developer's Experience As A Ruby Developer
Venturing Into The Wild: A .NET Developer's Experience As A Ruby DeveloperVenturing Into The Wild: A .NET Developer's Experience As A Ruby Developer
Venturing Into The Wild: A .NET Developer's Experience As A Ruby DeveloperJon Kruger
 
Reactive Type safe Webcomponents with skateJS
Reactive Type safe Webcomponents with skateJSReactive Type safe Webcomponents with skateJS
Reactive Type safe Webcomponents with skateJSMartin Hochel
 
Building DSLs with Groovy
Building DSLs with GroovyBuilding DSLs with Groovy
Building DSLs with GroovySten Anderson
 
A Few of My Favorite (Python) Things
A Few of My Favorite (Python) ThingsA Few of My Favorite (Python) Things
A Few of My Favorite (Python) ThingsMichael Pirnat
 
Debugging in drupal 8
Debugging in drupal 8Debugging in drupal 8
Debugging in drupal 8Allie Jones
 
Ejb3 Struts Tutorial En
Ejb3 Struts Tutorial EnEjb3 Struts Tutorial En
Ejb3 Struts Tutorial EnAnkur Dongre
 
Ejb3 Struts Tutorial En
Ejb3 Struts Tutorial EnEjb3 Struts Tutorial En
Ejb3 Struts Tutorial EnAnkur Dongre
 
ActiveJDBC - ActiveRecord implementation in Java
ActiveJDBC - ActiveRecord implementation in JavaActiveJDBC - ActiveRecord implementation in Java
ActiveJDBC - ActiveRecord implementation in Javaipolevoy
 
fuser interface-development-using-jquery
fuser interface-development-using-jqueryfuser interface-development-using-jquery
fuser interface-development-using-jqueryKostas Mavridis
 
The Ring programming language version 1.9 book - Part 54 of 210
The Ring programming language version 1.9 book - Part 54 of 210The Ring programming language version 1.9 book - Part 54 of 210
The Ring programming language version 1.9 book - Part 54 of 210Mahmoud Samir Fayed
 

Similaire à Advanced GORM - Performance, Customization and Monitoring (20)

jQuery in the [Aol.] Enterprise
jQuery in the [Aol.] EnterprisejQuery in the [Aol.] Enterprise
jQuery in the [Aol.] Enterprise
 
Clojure and Modularity
Clojure and ModularityClojure and Modularity
Clojure and Modularity
 
REST APIs in Laravel 101
REST APIs in Laravel 101REST APIs in Laravel 101
REST APIs in Laravel 101
 
Oscon Java Testing on the Fast Lane
Oscon Java Testing on the Fast LaneOscon Java Testing on the Fast Lane
Oscon Java Testing on the Fast Lane
 
Converting your JS library to a jQuery plugin
Converting your JS library to a jQuery pluginConverting your JS library to a jQuery plugin
Converting your JS library to a jQuery plugin
 
Venturing Into The Wild: A .NET Developer's Experience As A Ruby Developer
Venturing Into The Wild: A .NET Developer's Experience As A Ruby DeveloperVenturing Into The Wild: A .NET Developer's Experience As A Ruby Developer
Venturing Into The Wild: A .NET Developer's Experience As A Ruby Developer
 
Reactive Type safe Webcomponents with skateJS
Reactive Type safe Webcomponents with skateJSReactive Type safe Webcomponents with skateJS
Reactive Type safe Webcomponents with skateJS
 
Building DSLs with Groovy
Building DSLs with GroovyBuilding DSLs with Groovy
Building DSLs with Groovy
 
Jquery fundamentals
Jquery fundamentalsJquery fundamentals
Jquery fundamentals
 
A Few of My Favorite (Python) Things
A Few of My Favorite (Python) ThingsA Few of My Favorite (Python) Things
A Few of My Favorite (Python) Things
 
Debugging in drupal 8
Debugging in drupal 8Debugging in drupal 8
Debugging in drupal 8
 
Ejb3 Struts Tutorial En
Ejb3 Struts Tutorial EnEjb3 Struts Tutorial En
Ejb3 Struts Tutorial En
 
Ejb3 Struts Tutorial En
Ejb3 Struts Tutorial EnEjb3 Struts Tutorial En
Ejb3 Struts Tutorial En
 
ActiveJDBC - ActiveRecord implementation in Java
ActiveJDBC - ActiveRecord implementation in JavaActiveJDBC - ActiveRecord implementation in Java
ActiveJDBC - ActiveRecord implementation in Java
 
JS Essence
JS EssenceJS Essence
JS Essence
 
fuser interface-development-using-jquery
fuser interface-development-using-jqueryfuser interface-development-using-jquery
fuser interface-development-using-jquery
 
Django Good Practices
Django Good PracticesDjango Good Practices
Django Good Practices
 
The Ring programming language version 1.9 book - Part 54 of 210
The Ring programming language version 1.9 book - Part 54 of 210The Ring programming language version 1.9 book - Part 54 of 210
The Ring programming language version 1.9 book - Part 54 of 210
 
Factory girl
Factory girlFactory girl
Factory girl
 
Os Davis
Os DavisOs Davis
Os Davis
 

Plus de Burt Beckwith

What's New in spring-security-core 2.0
What's New in spring-security-core 2.0What's New in spring-security-core 2.0
What's New in spring-security-core 2.0Burt Beckwith
 
Grails Plugin Best Practices
Grails Plugin Best PracticesGrails Plugin Best Practices
Grails Plugin Best PracticesBurt Beckwith
 
Testing the Grails Spring Security Plugins
Testing the Grails Spring Security PluginsTesting the Grails Spring Security Plugins
Testing the Grails Spring Security PluginsBurt Beckwith
 
Securing Grails Applications
Securing Grails ApplicationsSecuring Grails Applications
Securing Grails ApplicationsBurt Beckwith
 
Under the Hood: Using Spring in Grails
Under the Hood: Using Spring in GrailsUnder the Hood: Using Spring in Grails
Under the Hood: Using Spring in GrailsBurt Beckwith
 

Plus de Burt Beckwith (6)

What's New in spring-security-core 2.0
What's New in spring-security-core 2.0What's New in spring-security-core 2.0
What's New in spring-security-core 2.0
 
Grails Transactions
Grails TransactionsGrails Transactions
Grails Transactions
 
Grails Plugin Best Practices
Grails Plugin Best PracticesGrails Plugin Best Practices
Grails Plugin Best Practices
 
Testing the Grails Spring Security Plugins
Testing the Grails Spring Security PluginsTesting the Grails Spring Security Plugins
Testing the Grails Spring Security Plugins
 
Securing Grails Applications
Securing Grails ApplicationsSecuring Grails Applications
Securing Grails Applications
 
Under the Hood: Using Spring in Grails
Under the Hood: Using Spring in GrailsUnder the Hood: Using Spring in Grails
Under the Hood: Using Spring in Grails
 

Dernier

Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsAhmed Mohamed
 
VK Business Profile - provides IT solutions and Web Development
VK Business Profile - provides IT solutions and Web DevelopmentVK Business Profile - provides IT solutions and Web Development
VK Business Profile - provides IT solutions and Web Developmentvyaparkranti
 
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Angel Borroy López
 
Precise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive GoalPrecise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive GoalLionel Briand
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureDinusha Kumarasiri
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...OnePlan Solutions
 
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Cizo Technology Services
 
Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Mater
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtimeandrehoraa
 
PREDICTING RIVER WATER QUALITY ppt presentation
PREDICTING  RIVER  WATER QUALITY  ppt presentationPREDICTING  RIVER  WATER QUALITY  ppt presentation
PREDICTING RIVER WATER QUALITY ppt presentationvaddepallysandeep122
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based projectAnoyGreter
 
Post Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on IdentityPost Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on Identityteam-WIBU
 
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)jennyeacort
 
Machine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringMachine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringHironori Washizaki
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceBrainSell Technologies
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfAlina Yurenko
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfFerryKemperman
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024StefanoLambiase
 
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdfInnovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdfYashikaSharma391629
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEEVICTOR MAESTRE RAMIREZ
 

Dernier (20)

Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML Diagrams
 
VK Business Profile - provides IT solutions and Web Development
VK Business Profile - provides IT solutions and Web DevelopmentVK Business Profile - provides IT solutions and Web Development
VK Business Profile - provides IT solutions and Web Development
 
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
 
Precise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive GoalPrecise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive Goal
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with Azure
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
 
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
 
Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtime
 
PREDICTING RIVER WATER QUALITY ppt presentation
PREDICTING  RIVER  WATER QUALITY  ppt presentationPREDICTING  RIVER  WATER QUALITY  ppt presentation
PREDICTING RIVER WATER QUALITY ppt presentation
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based project
 
Post Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on IdentityPost Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on Identity
 
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
 
Machine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringMachine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their Engineering
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. Salesforce
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdf
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
 
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdfInnovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdf
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEE
 

Advanced GORM - Performance, Customization and Monitoring

  • 1. Advanced GORM - Performance, Customization and Monitoring Burt Beckwith
  • 2. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. Overview • Demonstration of potential performance issues with mapped collections in GORM • Using the Hibernate 2nd -level cache • Monitoring and managing 2nd -level caches
  • 3. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. Standard Grails One-to-Many Library has many Visits: class Library { String name static hasMany = [visits: Visit] } class Visit { String personName Date visitDate = new Date() static belongsTo = [library: Library] }
  • 4. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. Standard Grails One-to-Many Usage: • object-oriented way to record visits to a library • convenience methods addToVisits()/removeFromVisits() handle add/remove and cascading save/delete Library library = new Library(name: 'Carnegie').save() ... library.addToVisits(new Visit(personName:'me')) library.save() ... library.addToVisits(new Visit(personName:'me2')) library.save()
  • 5. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. Standard Grails One-to-Many DDL (use grails schema-export to generate): create table library ( id bigint generated by default as identity (start with 1), version bigint not null, name varchar(255) not null, primary key (id) ); create table visit ( id bigint generated by default as identity (start with 1), version bigint not null, library_id bigint not null, person_name varchar(255) not null, visit_date timestamp not null, primary key (id) ); alter table visit add constraint FK6B04D4B4AEC8BBA foreign key (library_id) references library;
  • 6. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. So What's the Problem? • “hasMany = [visits: Visit]” creates a Set (org.hibernate.collection.PersistentSet) in Library – the “inverse” collection in traditional Hibernate • Adding to the Set requires loading all instances from the database to guarantee uniqueness, even if you know the new item is unique • Likewise for a mapped List – Hibernate pulls the entire collection to maintain the correct order, even if you're adding to the end of the list • In traditional Hibernate you could map the collection as a Bag, which is just a regular Collection with no ordering or uniqueness guarantees, but Grails doesn't support Bags
  • 7. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. So What's the Problem? • You get a false sense of security since it's a lazy- loaded collection (by default); loading a Library doesn't load all Visits, but that's only partially helpful • Works fine in development when you only have a few Visits, but imagine when you deploy to production and you have 1,000,000 Visits and want to add one more • Risk of artificial optimistic locking exceptions; altering a mapped collection bumps the version, so simultaneous Visit creations can break but shouldn't
  • 8. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. Demo
  • 9. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. Ok, So What's the Solution? Remove the collection: class Library { String name } class Visit { String personName Date visitDate = new Date() Library library }
  • 10. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. How does that affect usage? • Different syntax for persisting a Visit • No cascading; to delete a Library you need to delete its Visits first (in a transactional service method!) Library library = new Library(name: 'Carnegie').save() ... new Visit(personName:'me', library: library).save() ... new Visit(personName:'me2', library: library).save()
  • 11. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. How does that affect usage? • If you want to know all Visits for a Library, use a custom finder: • This is actually significantly more convenient since you can query for the 10 most recent, just last month's visits, etc. def visits = Visit.findAllByLibrary(library) def last10 = Visit.executeQuery( "from Visit v where v.library=:library " + "order by v.visitDate desc", [library: library], [max: 10])
  • 12. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. How does this affect DDL? Not at all, both approaches set visit.library_id: create table library ( id bigint generated by default as identity (start with 1), version bigint not null, name varchar(255) not null, primary key (id) ); create table visit ( id bigint generated by default as identity (start with 1), version bigint not null, library_id bigint not null, person_name varchar(255) not null, visit_date timestamp not null, primary key (id) ); alter table visit add constraint FK6B04D4B4AEC8BBA foreign key (library_id) references library;
  • 13. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. Standard Grails Many-to-Many User has many Roles, Role has many Users: class User { static hasMany = [roles: Role] String username } class Role { static belongsTo = User static hasMany = [users: User] String name }
  • 14. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. Standard Grails Many-to-Many Usage: Role roleUser = new Role(name: 'ROLE_USER').save() Role roleAdmin = new Role(name: 'ROLE_ADMIN').save() … User user1 = new User(username:'user1') user1.addToRoles(roleUser) user1.save() ... User user2 = new User(username:'user2') user2.addToRoles(roleAdmin) user2.save()
  • 15. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. Standard Grails Many-to-Many • Object-oriented approach to assigning a Role to a User • Syntax is very similar to One-to-many • Convenience methods addToRoles() and removeFromRoles() handle adding to/removing from mapped collection and cascading save/delete
  • 16. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. Standard Grails Many-to-Many DDL (use grails schema-export to generate): create table role ( id bigint generated by default as identity (start with 1), version bigint not null, name varchar(255) not null, primary key (id) ); create table user ( id bigint generated by default as identity (start with 1), version bigint not null, username varchar(255) not null, primary key (id) ); create table user_roles ( user_id bigint not null, role_id bigint not null, primary key (user_id, role_id) ); alter table user_roles add constraint FK7342994952388A1A foreign key (role_id) references role; alter table user_roles add constraint FK73429949F7634DFA foreign key (user_id) references user;
  • 17. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. So What's the Problem? • "hasMany = [users: User]" and "hasMany = [roles: Role]" create a Set (org.hibernate.collection.PersistentSet) in both User and Role • Adding a Role to a User's 'roles' Set requires loading all instances of the User's Roles (for uniqueness check) AND all other Users who already have that Role from the database • This is because Grails automatically maps both collections for you and populates both - "user.addToRoles(role)" and "role.addToUsers(user)" are equivalent because it's bidirectional
  • 18. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. So What's the Problem? • Works fine in development when you only have a few Users, but imagine when you deploy to production and you have 1,000,000 registered site users with ROLE_MEMBER and want to add one more • Risk of artificial optimistic locking exceptions; altering a mapped collection bumps the version, so simultaneous Role grants can break but shouldn't
  • 19. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. Demo
  • 20. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. Ok, So What's the Solution? Remove the collections and map the join table: class User { String username } class Role { String name } class UserRole implements Serializable { User user Role role static mapping = { table 'user_roles' version false id composite: ['user', 'role'] } }
  • 21. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. Ok, So What's the Solution? We can add some helper methods to UserRole: class UserRole implements Serializable { ... static UserRole create(User user, Role role, boolean flush = false) { UserRole userRole = new UserRole(user: user, role: role) userRole.save(flush: flush, insert: true) return userRole } static boolean remove(User user, Role role, boolean flush = false) { UserRole userRole = UserRole.findByUserAndRole(user, role) return userRole ? userRole.delete(flush: flush) : false } static void removeAll(User user) { executeUpdate("DELETE FROM UserRole WHERE user=:user", [user: user]) } }
  • 22. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. Ok, So What's the Solution? and restore a 'roles' pseudo-collection back in User: class User { String username Set<Role> getRoles() { UserRole.findAllByUser(this).collect { it.role } as Set } boolean hasRole(Role role) { UserRole.countByUserAndRole(this, role) > 0 } }
  • 23. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. How does that affect usage? • Different syntax for granting a Role • No cascading; to delete a User you you need to delete (disassociate) its Roles first (use UserRole.removeAll(User user)) User user = … Role role = … UserRole.create user, role – or – UserRole.remove user, role
  • 24. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. So Never Use Mapped Collections? • No, you need to examine each case • The standard approach is fine if the collections are reasonably small – both sides in the case of Many-to-Many • The collections will contain proxies, so they're smaller than real instances until initialized, but still a memory concern
  • 25. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. Using Hibernate 2nd -Level Cache DataSource.groovy: dataSource { pooled = true driverClassName = 'com.mysql.jdbc.Driver' url = ... username = ... password = ... dialect = org.hibernate.dialect.MySQL5InnoDBDialect } hibernate { cache.use_second_level_cache = true cache.use_query_cache = true cache.provider_class = 'org.hibernate.cache.EhCacheProvider' }
  • 26. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. Mapping in Domain Classes class Book { … static mapping = { cache true } } class Country { … static mapping = { cache usage: 'read-only' } } class Author { … static hasMany = [books:Book] static mapping = { books cache: true } }
  • 27. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. Usage Notes • The 1st -level cache is the Hibernate Session • Can significantly reduce database load by keeping instances in memory • Can be distributed between multiple servers to let one instance load from the database and share updated instances, avoiding extra database trips • "cache true" creates a read-write cache, best for read- mostly objects since frequently-updated objects will result in excessive cache invalidation (and network traffic when distributed) • "cache usage: 'read-only'" creates a read-only cache, best for lookup data (e.g. Countries, States, Zip Codes, Roles, etc.) that never change
  • 28. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. Usage Notes • DomainClass.get() always uses the 2nd-level cache • By default nothing else always uses the cache but can be overridden
  • 29. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. Configuring with ehcache.xml • If you don't create an ehcache.xml file in the classpath (either grails-app/conf or src/java) EhCache will use built- in defaults and you'll see warnings at startup <ehcache> <diskStore path="java.io.tmpdir" /> <defaultCache maxElementsInMemory="10000" eternal="false" ... /> <cache name="com.foo.bar.Thing" maxElementsInMemory="10000" eternal="false" overflowToDisk="false" maxElementsOnDisk="0" />
  • 30. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. Configuring with ehcache.xml <cache name="com.foo.bar.Zipcode" maxElementsInMemory="100000" eternal="true" overflowToDisk="false" maxElementsOnDisk="0" /> <cache name="org.hibernate.cache.StandardQueryCache" maxElementsInMemory="50" eternal="false" overflowToDisk="false" maxElementsOnDisk="0" timeToLiveSeconds="120" /> <!-- timestamps of the most recent updates to queryable tables --> <cache name="org.hibernate.cache.UpdateTimestampsCache" maxElementsInMemory="5000" eternal="true" overflowToDisk="false" maxElementsOnDisk="0" /> </ehcache>
  • 31. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. Query Cache • Criteria queries: • HQL queries: • In dynamic finders (new in 1.1) def criteria = DomainClass.createCriteria() def results = criteria.list { cacheable(true) } DomainClass.withSession { session -> return session.createQuery( "select ... from … where ...") .setCacheable(true).list() } } def person = Person.findByFirstName("Fred", [cache:true])
  • 32. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. Hibernate query cache considered harmful? • Most queries are not good candidates for caching; must be same query and same parameters • Updates to domain classes will pessimistically flush all potentially affected cached results • DomainClass.list() is a decent candidate if there aren't any (or many) updates and the total number isn't huge • Great blog post by Alex Miller (of Terracotta) http://tech.puredanger.com/2009/07/10/hibern ate-query-cache/
  • 33. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. 2nd -Level Cache API • evict one instance – sessionFactory.evict(DomainClass, id) • evict all instances – sessionFactory.evict(DomainClass) • evict one instance's collection – sessionFactory.evictCollection( 'DomainClass.collectionName', id) • evict all collections of DomainClass – sessionFactory.evictCollection( 'DomainClass.collectionName')
  • 34. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. 2nd -Level Cache API • sessionFactory.statistics (org.hibernate.stat.Statistics) methods: – statistics.queryCacheHitCount – statistics.queryCacheMissCount – statistics.queryCachePutCount – statistics.secondLevelCacheHitCount – statistics.secondLevelCacheMissCount – statistics.secondLevelCachePutCount – statistics.secondLevelCacheRegionNames
  • 35. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. 2nd -Level Cache API • statistics.getSecondLevelCacheStatistics(cacheName) (org.hibernate.stat.SecondLevelCacheStatistics) methods: – cacheStatistics.elementCountInMemory – cacheStatistics.elementCountOnDisk – cacheStatistics.hitCount – cacheStatistics.missCount – cacheStatistics.putCount – cacheStatistics.sizeInMemory
  • 36. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. Monitoring Demo
  • 37. SpringOne 2GX 2009. All rights reserved. Do not distribute without permission. Q&A