- Tl;dr We probably want to keep some level of manual flushing, but there are a lot of flushes we can remove!
-
Currently, we create Hibernate Sessions with FlushMode.MANUAL (code pointer and code pointer). This mode delegates all flushing operations to us.
- Initially I thought about changing our Sessions to have FlushMode.COMMIT or FlushMode.AUTO, both of which automatically flush before each Transaction commit. However, this looks to generate flushes that contain no actual changes, which we want to avoid.
-
The methods of
GenericHibernateDao
execute their queries withGenericHibernateDao::execute
.exectue
wraps each query in a Transaction.GenericHibernateDao::flush
itself callsexecute
. So each call todao.flush()
that we remove will save us a Transaction.
-
We only want to Flush on queries that update the db. All such queries will go through
GenericHibernateDao::save
orGenericHibernateDao::delete
.- These methods have a
flush
parameter that controlls if we flush or not. - Of the Public methods of
GenericHibernateDao
which callsave
anddelete
, onlysaveMapObject
anddeleteMapObject
call withflush=False
.
- These methods have a
-
Therefore, we can immediatley make the following changes:
- Remove
dao.flush()
calls wheredao
is always aSQLiteDao
: Example.SQLiteDao::flush
is a noop. - Remove
dao.flush()
calls after calls to methods ofGenericHibernateDao
that are notsaveMapObject
ordeleteMapObject
. These methods will callGenericHibernateDao::[save/delete]
withflush=True
, so there is no need for a manual flush afterward. Example. - Confirmed with Hibernate logging. In these cases we're doing a Trasaction containing a Flush that has no updates.
- Ex: 2022-09-19 12:53:21 AbstractFlushingEventListener [DEBUG] Flushed: 0 insertions, 0 updates, 0 deletions to 12 objects 2022-09-19 12:53:21 AbstractFlushingEventListener [DEBUG] Flushed: 0 (re)creations, 0 updates, 0 removals to 87 collections
- Remove
-
What to do with
GenericHibernateDao::[save/delete]MapObject
?- Consider the case were
[save/delete]MapObject
is called once, followed bydao.flush()
. Example.- We can save a Transaction here by making a version of
saveMapObject
that callssave
withflush=True
.
- We can save a Transaction here by making a version of
- The cases that are more interesting are where we perform several
[save/delete]MapObject
calls, followed by a flush afterward, Example.- This allows us "queue up" many updates in the Hibernate persistence context, then flush them at once.
- I think this is good behavior to keep as it reduces the number of flushes.
- There are some places we can cut down on flushes here as well.
- Another way to deal with this would be providing a mechanism to put all of these calls within one transaction. However, that change would be more work and I'm not sure how much gain would come of it.
- Consider the case were
- These Job classes all behave similarly. They create a session with FlushMode.COMMIT, start a transaction, call some dao methods, and commit a transaction.
- However, each dao method will run its own transaction within
execute
and performs a flush for the update methods that are called - So, we can probably change the FlushMode to MANUAL here.
- Furthermore, since each individual query runs its own transaction, do we need to wrap everything in an outer transaction?
- Keep the
flush
parameter and behavior of theGenericHibernateDao::[save/delete]
methods to keep the "queuing" behaviour ofGenericHibernateDao::[save/delete]MapObject
- Go ahead with creating a PR removing unnecessary flushes for both the non-job and job code.
- To address the question on the card. I don't think the related objects case of Map and Account is relevant. We don't save maps to the UserAccount object and instead get all maps in the CollaborativeMapObject table tagged with the current UserAccount.
- We setup the Hibernate Sessions within Spring using Spring's OpenSessionInViewFilter. Docs
- Quoting the docs, Spring assumes that OpenSessionInViewFilter will
be used in combination with service layer transactions that care for the flushing: The active transaction manager will temporarily change the flush mode to FlushMode.AUTO during a read-write transaction, with the flush mode reset to FlushMode.MANUAL at the end of each transaction.
- However as far as I can tell we do not use Spring's transaction management system at all.
- If using their system, we'd annotate methods that update the db (i.e.
GenericHibernateDao::[save/delete]
) with@Transactional(read-only=False)
and ottherGenericHibernateDao
methods with@Transactional(read-only=True)
. That would achieve the same behaviour we want to achieve of only flushing on updates. - I don't think we need to do this at all, but I came across it in my investigation.
- Quoting the docs, Spring assumes that OpenSessionInViewFilter will