Multi-tenant entities not eligible for hibernate 2nd level caching
- Dominant language
- Groovy
- Stars
- 2.9k
- Forks
- 975
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 92
Description
In testing multi-tenancy for our application I realized that any entity which implements MultiTenant is not eligible for 2nd level caching at all in Hibernate.
This is currently by design in `AbstractHibernateGormStaticApi.groovy` in the `get(...)` method:
```
if(persistentEntity.isMultiTenant()) {
// for multi-tenant entities we process get(..) via a query
(D)hibernateTemplate.execute( { Session session ->
def criteria = session.createCriteria(persistentEntity.javaClass)
criteria.add Restrictions.idEq(id)
firePreQueryEvent(session,criteria)
def result = (D) criteria.uniqueResult()
firePostQueryEvent(session, criteria, result)
return proxyHandler.unwrap( result )
} )
}
else {
// for non multi-tenant entities we process get(..) via the second level cache
return (D)proxyHandler.unwrap(
hibernateTemplate.get(persistentEntity.javaClass, id)
)
}
```
Hibernate 5.1 and later support cache aware multi-tenancy since the `QueryKey` class used for querying the second level cache is tenant aware (it includes the `tenantIdentifier` in the key).
However, it seems like Grails isn't really configuring the hibernate multi-tenancy (or not configuring it fully) since the `sessionOptions` on the SessionFactory configured by Grails indicates tenancy of 'NONE' even when multi-tenancy is enable for Grails. Perhaps this is to abstract multi-tenancy to support more datastore types, I'm not sure.
This is a huge performance impact for our application as most of our domain objects needs to exist in both tenants and therefore don't make good use of the 2nd level cache, causing thousands of extract queries for some things.
### Steps to Reproduce
1. Create a domain object that implements MultiTenant and make it cached (nonstrict-read-write) in our case.
2. Fetch that object multiple times in different sessions and observe queries each time
### Expected Behaviour
Ideally, Grails should configure and defer the tenancy to Hibernate and use the configured `hibernateTemplate.get(...)` for everything. As long as hibernate is "tenant-aware", it looks like it should respect the tenant when pulling from the cache.
Contributor guide
Research direction
Start in AbstractHibernateGormStaticApi.groovy, especially the get(...) branch for multi-tenant entities, and inspect how Grails configures the SessionFactory sessionOptions. Reproduce the issue with a cached MultiTenant domain object fetched across sessions, then verify that tenant-aware Hibernate retrieval uses the second-level cache without cross-tenant results.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- groovy
- Domain
- backend, databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100