Search code examples
spring-boothibernatespring-datamicronaut-data

Is Spring Data data-safe from/to 3rd party queries?


I am confused about Spring Data/Hibernate's black-box persistence-related stuff I read about - mostly query caching and flushing.

As far as I understand:

Caching queries:
Spring data does not run queries in a transaction directly on a database, but rather caches them in memory until some (the latest possible) moment - that being a transaction commit in the database. This is because of performance - so that code doesn't have to reach the database on every repository call.

Flushing:
When it's needed to interact with the database - e.g. to receive generated (numeric id) or default values - code can flush a repository to run queries directly on the database (still in a single transaction). This makes it possible to do e.g. data bindings via foreign keys, etc...

I need to know the following things:

  • Is Spring Data completely data-safe to 3rd party data manipulation (e.g. other applications, db console,..)? I mean - is it possible that there can be an inconsistency in transactivity/flushing with other clients?
  • If not, what are the settings to achieve this?
  • Does Micronaut data work the same way?

Solution

  • Before answering your questions, let me make a couple clarifications.

    Spring Data is a wide umbrella that can cover many data stores. For example, there is Spring Data JDBC which communicates with the JDBC driver directly; there is Spring Data Redis for providing repository access to a Redis server; and, most relevant to your question, there is Spring Data JPA, which uses a JPA implementation (by default Hibernate) to interact with your database through JPA.

    The caching you're referring to is Hibernate's first-level cache, the Persistence Context. It's effectively a cache of JPA entities. At flush time, Hibernate will take "saved" entities (merged/persisted, triggered by calling the #save method on Spring Data repositories) and generate an appropriate INSERT/UPDATE/DELETE query to update the data in the database.


    Is Spring Data completely data-safe to 3rd party data manipulation (e.g. other applications, db console,..)? I mean - is it possible that there can be an inconsistency in transactivity/flushing with other clients?

    Sounds like you're asking about Isolation, and the answer is going to depend on what you consider to be "data-safe" amongst the isolation levels. Most databases default to "READ COMMITTED", in which data from committed concurrent transactions can be read in the current transaction, and it's as if uncommitted changes have never taken place. I'm going to assume that's the isolation level you will stick with. More strict isolation levels requires more careful thought to avoid excessive locking.

    Under a READ COMMITTED isolation level, the caching that Hibernate does is (in terms of read phenomena) no different from if the same statements were being executed via a non-JPA application/database console/etc. That's because transactions only read committed data- so deferring the INSERTs/UPDATEs does not matter because their new state only becomes visible after COMMIT, regardless of when the INSERT/UPDATE itself was executed by the database.

    The caching of entities is done using the Persistence Context. The Persistence Context is bound to the Hibernate Session. And the Hibernate Session is opened at the start of a Spring transaction, and closed at the end of it. Therefore the caching of modified entities does not outlive the database transaction. Note that there's a couple of exceptions for Open Session In View, but it's still the case that modifications to entities get flushed/committed to DB at the end of the session.


    If not, what are the settings to achieve this?

    Again, the "data-safe"-ness depends on the default isolation level of your database. If you believe that you need a different isolation level than the default, you can change it in a few ways:

    1. Change your entire database's isolation level, if allowed. This will depend on which DBMS you're using, so you would need to find the documentation for your respective DBMS.
    2. Change Hibernate's configured transaction isolation level, to which I'll refer to this other SO answer that also includes a description of the isolation levels
    3. Set the isolation level using Spring's @Transactional annotation. For example, a SERIALIZABLE isolation level could be set by annotating your transactional method with @Transactional(isolation = Isolation.SERIALIZABLE). See the Javadoc for other options and clarification.

    Does Micronaut data work the same way?

    I've not used Micronaut data, but from what I can tell, the answer to this will also just depend on how you're using Micronaut data. Micronaut Data JDBC (and Spring Data JDBC, for that matter) has no entity caching. It is my understanding Micronaut Data JPA still just delegates to Hibernate, in which case, yes, Hibernate will still perform entity caching using the Persistence Context.

    That said, as I mentioned before, most often that will not be concerning at the READ COMMITTED isolation level due to the behavior of that isolation level.