2

I have a simple controller method, where I create a new object Car and then set its name to Audi:

@GetMapping(value = "/resource")
public ResponseEntity visit() {
    Car car = carRepo.save(new Car("VolksWagen")); // Car should be managed now?
    car.setName("Audi"); // <-- has no effect on database state

    return ResponseEntity.ok().build();
}

In the database, it never becomes an Audi, but stays a VolksWagen.

Why does this happen? Shouldn't the newly created Car be in managed state for the persistence context?

Note: It works if I add the @Transactional annotation. I thought it would be enough if OSIV is enabled. What am I misunderstanding about OSIV and @Transactional?

Snackoverflow
  • 5,332
  • 7
  • 39
  • 69
  • 1
    OSIV leave the *session* open, in order to be able to lazy-load associations when rendering the view. But it doesn't leave the *transaction* open. The changes have already been committed, and later changes won't be persisted since later changes are ever flushed nor committed (and since changes are not supposed to happen in the first place) – JB Nizet Apr 19 '19 at 10:20
  • 1
    OSIV is a dirty hack anyway, since the data loaded after the transaction is committed is possibly inconsistent with the data loaded inside the transaction. I would avoid it. https://vladmihalcea.com/the-open-session-in-view-anti-pattern/ – JB Nizet Apr 19 '19 at 10:21
  • 1
    @JBNizet My application is actually just an API, so there's no point to use OSIV. I somehow managed to mix up OSIV with `@Transactional` in my head, but now I understand that they are completely different things. Thanks! – Snackoverflow Apr 19 '19 at 10:25

2 Answers2

3

Open Session In View (OSIV) leaves the session open, in order to be able to lazy-load associations when rendering the view. But it doesn't leave the transaction open.

The changes have already been committed, and later changes won't be persisted since later changes are ever flushed nor committed (and since changes are not supposed to happen in the first place)

OSIV is a dirty hack anyway, since the data loaded after the transaction is committed is possibly inconsistent with the data loaded inside the transaction. I would avoid it. See https://vladmihalcea.com/the-open-session-in-view-anti-pattern for more reasons.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
0

carRepo.save do a persist or a merge? if you are using merge pick up the result of the merge!

"Persist takes an entity instance, adds it to the context and makes that instance managed (ie future updates to the entity will be tracked).

Merge creates a new instance of your entity, copies the state from the supplied entity, and makes the new copy managed. The instance you pass in will not be managed (any changes you make will not be part of the transaction - unless you call merge again)." as described in this answer

Marco74
  • 36
  • 5
  • I forgot to mention, that the repository is an extension of the `CrudRepository`. Therefore, `save()` in this case, when creating a new entity, should call `persist()` internally. – Snackoverflow Apr 19 '19 at 10:43