1

I have two entities with one-to-one association. And some services that works with them in parallel. I need to delete one, but sometimes i have DataIntegrityViolationException, that as i understand means that i can't delete some entity while other has foreign key on it.

Here is my entities:

public class Foo{

    @Id
    @GeneratedValue
    private Long id;

}

and:

public class Bar{

    @Id
    @GeneratedValue
    private Long id;

    @ManyToOne
    private Foo foo;

}

Method that doesn't work (all repos extends from JpaRepository):

    @Transactional
    public void deleteFoo(Long fooId) {        
            barRepository.deleteAllByFooId(fooId);            
            fooRepository.deleteById(fooId);
    }

And some method that works in parallel and breaks everything:

    @Transactional
    public void method(Long fooId) {        
            ...
            Foo foo = fooRepository.findById(fooId);
            barRepository.save(new Bar(foo));
            ...
    }

So i have ConstraintViolationException, as i understand because im trying to delete Foo but i have that new Bar(foo) in method that wasn't deleted by barRepository.deleteAllByFooId(fooId) in deleteFoo .

I need some approach like "delete method should wait until all current transactions finishes and then run only one transaction". Can't use KeyLockManager because real structure of project already enough complicated and if i use it it should be same lock in many classes.

Dedmikash
  • 13
  • 3
  • "I need some approach like "delete method should wait until all current transactions finishes and then run only one transaction"." that would be a horrible solution, sure it would fix your problem, but it would degrade the performance of the database significantly. You should check your program flow, verify your transaction boundaries, and then when a transaction fails, either retry it or return an error. – Kayaman Oct 10 '19 at 08:05
  • To answer the question would depend on knowing what you want to do. If `barRepository.save(new Bar(foo));` is called for a deleted foo then what should happen? – Alan Hay Oct 10 '19 at 08:23
  • Alan, ok if in this case i have some exception and new bar wouldnt be saved. – Dedmikash Oct 10 '19 at 08:39
  • Kayaman, agree with you, thats only working example. – Dedmikash Oct 10 '19 at 08:40
  • Well, catch the exception, re-throw it throw it as a checked exception and have the calling code handle it. – Alan Hay Oct 10 '19 at 08:44
  • Problem is that delete method now throws exception, because there are not deleted bar that refers to foo which i want to delete, so transaction failed and all roll backed. – Dedmikash Oct 10 '19 at 08:51
  • Sorry but I have no idea what you actually want to happen. – Alan Hay Oct 10 '19 at 11:24
  • Alan, just successfully delete foo and it's bars. – Dedmikash Oct 10 '19 at 11:38

1 Answers1

-2

The problem is that you try to delete entity that being used in transaction. To close transaction you could use repository's save() method.

Also you should look at cascades and orphan removal. Use like this:

In Bar entity:

@ManyToOne(cascade = CascadeType.REMOVE, orphanRemoval = true)
private Foo foo;

And delete like so:

barRepository.save(bar);

or so:

ivanjermakov
  • 1,131
  • 13
  • 24
  • They can be useful yes (especially if you're manually doing the cascade logic anyway), but this doesn't solve the transaction issue. – Kayaman Oct 10 '19 at 08:07