Uploaded image for project: 'Hibernate ORM'
  1. Hibernate ORM
  2. HHH-9367

Concurrency issues caused by L1 (session) cache.

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major
    • Resolution: Rejected
    • Affects Version/s: None
    • Fix Version/s: None
    • Component/s: None
    • Labels:
      None
    • Bug Testcase Reminder (view):

      Bug reports should generally be accompanied by a test case!

    • Last commented by a user?:
      true

      Description

      I do not consider myself a Hibernate expert but I think I have done enough research to be sure that the issue I am about to describe is rooted in how Hibernate is designed. I hope there is a simple workaround because, I believe, this issue serious.

      Hibernate is used by several web frameworks, all 'manage' hibernate sessions and typically a single session is used for the scope of the request. I will use Grails as example.

      My understanding:
      (A) Based on my testing the following is true: if results of a query contain some objects that are already attached to the session, the attached objects are returned and these objects ARE NOT REFRESHED.

      Is my understanding correct? All tests I have done seem to indicate that it is.

      (I would really appreciate an answer why are objects in the session are not refreshed since, at this point, Hibernate should know if the data has changed). To my knowledge there is no way to ask Query object to refresh the objects in L1 cache. Please correct me if I am wrong. I have searched Query and Session API JavaDoc.

      This creates a very serious concurrency issue, which I will describe next:
      Please, assume no 2nd level cache is configured.

      Consider some type of logical assert about data. As an example I will use something like this:

      {{ If I query User entity for all objects with a nickname 'Bob' all results should have nickname 'Bob'. }}

      Many other asserts would do, for example: 'if I configure uniqueness constraint on DB, then results returned from a query should have unique names' would be another example).
      Application code may logically rely on such asserts. Unfortunately, these are not guaranteed to hold because of (A).

      So, let me assume that I have defined entity User which has, among other things, a properties called nickName and userName.
      Here is a how the above assertion breaks under concurrent use (shown in Groovy code to simplify the assert):

         def q0 = mysession.createQuery("select u from User u where fullName = :userName")
         q0.setParameter('userName', 'rpeszek')
         q0.list() //User rpeszek is placed on the session with his current nickName 'Troublemaker'
       
         ... concurrent activity changes nickName for rpeszek from 'Troublemaker' to 'Bob'
      
         def q = mysession.createQuery("select u from User u where nickName = :nickName")
         q.setParameter('nickName ', 'Bob')
         def users = q.list()
         assert users.every{ it.branch == 'Bob'} //FAILS because User rpeszek is returned 
                                                 //but value stored on the session is used which 
                                                 //still has 'Troublemaker'       
      

      All of this maybe more readable with using GORM niceties:

         //User rpeszek is placed on the session with his current nickName 'Troublemaker'
         User.findByUserName('rpeszek') 
       
         ... concurrent activity changes nickName for rpeszek from 'Troublemaker' to 'Bob'
      
         User.findAllByNickName('Bob').each{ it.nickName == 'Bob'}  //FAILS       
      

      The problem could be worked-around if Hibernate added ability to configure Query with an refresh option (so the objects already on the cache are refreshed with the new data obtained from that query.
      I would not expect associations themselves to get refreshed.) Without such refresh option the result of the query can be very wrong, the example I have just shown here is only one of many.

      This maybe considered a breaking change, but adding it as a configuration option would be welcomed.

      References:
      I described the issue in countless places and have got no meaningful replies. Current set of replies suggest that the community is completely unaware of this issue. I believe this issue is not unique to Grails and the impact is big.

      http://jira.grails.org/browse/GRAILS-11645
      http://stackoverflow.com/questions/25106636/strategies-for-dealing-with-concurrency-issues-caused-by-stale-domain-objects-g
      https://groups.google.com/forum/#!topic/grails-dev-discuss/wzekMGC0ibE

        Attachments

          Activity

            People

            • Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: