5

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.

Random42
  • 8,989
  • 6
  • 55
  • 86

2 Answers2

7

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.

dcernahoschi
  • 14,968
  • 5
  • 37
  • 59
  • So unless the type is set to extended, inside that method, a new entity manager is created, which doesn't have any managed entities? – Random42 Apr 29 '13 at 07:47
  • 1
    Yes, exactly. In the `otherLogicOnUser` method a new transaction is created and the persistence context should not be propagated unless you make it extended. – dcernahoschi Apr 29 '13 at 08:09
  • Use of an extended EntityManager was designed to be used in Stateful EJB's, it is not thread safe, and persistence context collisions can arise if a method using a transaction-scoped EntityManager invokes a method using an extended EntityManager in the same transaction. – German Apr 29 '13 at 22:31
4

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

Community
  • 1
  • 1
MariuszS
  • 30,646
  • 12
  • 114
  • 155