Concurrent requests operating on a one-to-one inverse relation can cause an inconsistent database, reproducible with the following example:

application test

  entity A {
    b -> B
  }
  
  entity B {
    a -> A (inverse=A.b)
  }
  
  var a1 := A{}

  define page root(){
    init{
      //will break db on concurrent access when a1.b was null, because there is no transaction conflict (only row in B is added), 
      // but there is a logical conflict (multiple B's pointing to A) which breaks subsequent queries
      a1.b := B{};
    }
  }
  

  define page root1(){
    init{
      a1.b := null;
    }
  }
  
      // start 2 apache benchmarks:
  // ab -n1000 -c10 http://localhost:8080/onetooneissue/
  // ab -n1000 -c10 http://localhost:8080/onetooneissue/root1

This is related to the mapping strategy of the Hibernate @OneToOne annotation: since only one side contains the reference (table of B), concurrent changes to a.b were a.b was null will not be detected as a transaction conflict (B’s are different and A is not touched).

Adding a uniqueness constraint on the reference column can cause the one-to-one inverse to not function at all, depending on the order of the B row edits.

The best solution seems to be to automatically increase the version property of an entity when an inverse property is changed, which would cause a transaction conflict in this example, instead of inconsistent data.

Submitted by Danny Groenewegen on 7 July 2010 at 13:41

On 7 July 2010 at 14:04 Danny Groenewegen commented:

Looks like this is a known open bug in Hibernate (voted it): http://opensource.atlassian.com/projects/hibernate/browse/HHH-4289

I’ll just add the fix to the WebDSL compiler in the mean time.


On 7 July 2010 at 15:55 Danny Groenewegen closed this issue.

On 7 July 2010 at 15:55 Danny Groenewegen commented:

fixed in rev 4047

also tried the many-to-many case, but there the version property seems to be updated on both sides preventing this issue

Log in to post comments