springhibernatespring-data-jpah2hibernate-cascade

Different Persistance Behaviour with In-Memory and MySQL DB


I have a parent entity and a child entity with a one to many relationship.

When using @DataJpaTest (i.e. configuring an in memory database), the following works as expected:

LOG.info("Creating stops");
Stop stop1 = new Stop(new Time(0), "Acton Town", new HashSet<>());
Set<Stop> stops = new HashSet<>();
stops.add(stop1);

LOG.info("Creating and persisting routes");
Route route = routeRepository.save(new Route("something", "return"));

LOG.info("Adding stops to route");
stops.forEach(route::addStop);

It inserts the route and each child correctly, and I can fetch the route later and get the same information back.

However, when I repeat this in my service while using a real datasource (a local MySQL DB), the CASCADE.ALL persist does not seem to occur, and I end up with no inserts for the stops but the route is persisted and assigned an ID.

I've followed the advice from around the site by using an 'addEntity' method in the parent that configured the bidirectional relationship, but it doesn't work outside of the test suite.

Does anyone know why this might be?


Solution

  • So one of the difference between my test and my service was the use of entityManager.flush().

    By adding @Transactional to my service method, the children get persisted, as this wraps the method call in an AOP proxy that essentially does this:

    transaction.begin()
    service.method()
    transaction.commit()
    

    It seems that my children weren't being persisted cause I essentially wasn't telling hibernate when to do it.

    The reason I hadn't noticed it before in other services, is that I was using CrudRepository to save entities which would make sure the id field was populated straight away, so this would essentially commit the transaction.

    It may also be affected by the multi-tenant enviroment I'm working in, where I have multiple transaction managers. If this is the case for you, you'll likely have to specify which one with the transactional annotation like so:

    @Transactional("nameoftransactionmanager")