问题
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
?
回答1:
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.
回答2:
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
来源:https://stackoverflow.com/questions/55760273/jpa-entity-not-managed-after-creation