Let's say we have the following piece of code:
@Entity
public class User {
@Id
private String name;
@OneToOne(cascade = CascadeType.ALL)
private Address address;
//getters and setters
}
@Entity
public class Address {
@Id
private int id;
private String street;
//getters and setters
}
@Stateless
//@Service
public class UserLogicClass {
@PersistenceContext
//@Autowired
private EntityManager entityManager;
public void logicOnUser(User user) {
if(logicOnAddress(user.getAddress()) {
otherLogicOnUser(user);
}
}
public boolean logicOnAddress(Address address) {
//
entityManager.find(address);//address becomes managed
//
}
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
//@Transactional(propagation = Propagation.REQUIRES_NEW)
public void otherLogicOnUser
//
entityManager.find(user);/*without annotation, user is not managed and address is managed, but with the transaction annotation is the address still managed?*/
//
}
}
The question relies in the comment from the last method; I am curios what happens in both Spring case and EJB case. Suppose Spring is configured with JTA transactions and any method called from this class would start a new transaction, just as in EJB.
When the transaction (in transaction-scoped persistence context) commits, entities managed by the persistence context become detached. If an application-managed persistence context is closed, all managed entities become detached. Using clear method.
If A is a detached entity, its state is copied into existing managed instance A' of the same entity identity, or a new managed copy of A is created. If A is a new entity, a new managed entity A' is created and the state of A is copied into A' . If A is an existing managed entity, it is ignored.
A detached entity (a.k.a. a detached object) is an object that has the same ID as an entity in the persistence store but that is no longer part of a persistence context (the scope of an EntityManager session).
You can detach an entity by calling Session. evict() . Other options are create a defensive copy of your entity before translation of values, or use a DTO instead of the entity in that code.
It's more an issue of JPA. The entityManager is not propagated to the new transaction unless you make it extended:
@PersistenceContext(type = PersistenceContextType.EXTENDED)
//@Autowired
private EntityManager entityManager;
Quote from the JPA 2.0 specs:
A container-managed persistence context may be defined to have either a lifetime that is scoped to a single transaction or an extended lifetime that spans multiple transactions, depending on the PersistenceContextType that is specified when its entity manager is created. This specification refers to such persistence contexts as transaction-scoped persistence contexts and extended persistence contexts respectively.
Note: Since this mechanism is based on proxies, only 'external' method calls coming in through the proxy will be intercepted. This means that 'self-invocation', i.e. a method within the target object calling some other method of the target object, won't lead to an actual transaction at runtime even if the invoked method is marked with @Transactional!
otherLogicOnUser() is invoked inside target object.
Read more: EJB Transactions in local method-calls
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With