0
votes

I am learning to use JPA. And I'm a little confused.

According JPA EntityManager manages transactions. But a design pattern is to inject the EntityManager in DAOs. So how is possible that are different EntityManager to the same transaction?

This is the case I want to solve

I have the DAOs defined

@Repository
JPARepository1 {

    @PersistenceContext
    protected EntityManager em;

    ....   

.

@Repository
JPARepository2 {

    @PersistenceContext
    protected EntityManager em;

    ....

I have a Service

@Service
public class ServiceImpl1 {

    @Autowired
    private JPARepository1 repo1;

    @Autowired
    private JPARepository2 repo2;  


    public void mainMethod(){
        Object o= transactionalMethod1();

        try{
            transactionalMethod2(o);
        }catch (Exception e){
            transactionalMethod3(o);
        }

    }

    private Object transactionalMethod1(){
        ....
    }

    private void transactionalMethod2(Object o){
        ....
    }


    private void transactionalMethod3(Object o){
        ....
    }

Then from @Controller I will invoke mainMethod(). What would be the right way to do transactional to transactionalMethod1, transactionalMethod2 and transactionalMethod3,within the same Service and using the same Repository's. I would like it if there is an exeption in transactionalMethod2, this abort the transaction, but keep the transactions of transactionalMethod1 and transactionalMethod3 Thanks, sorry for my English

1
Who says the EntityMangers being passed in are different?Tim Biegeleisen
Hmm, I do not know. So is singleton and all DAO's use the same EntityManger?user60108
I believe it is possible to have more than one EntityManager, but for your simply case you can expect to have only one.Tim Biegeleisen

1 Answers

2
votes

Usually you configure one EntityManager, so the wired manager is always the same, the one you configured. The instance of this manager though, is different in every wiring.

So, every transaction in your service uses a different instance of the EntityManager and thus every transaction invoked is seperated from each other.

As so, an exception in transactionalMethod2 doesn't necessarily affects the transactionalMethod1 and transactionalMethod3

What would be the right way to do transactional to transactionalMethod1, transactionalMethod2 and transactionalMethod3,within the same Service and using the same Repository's.

Now, you have two options to do service methods transactions

1) You could annotate your whole @Service like that:

@Service
@Transactional
public class ServiceImpl1 {
....

so every method declared here is also a transaction.

2) You could annotate each method as @Transactional:

@Transactional
private Object transactionalMethod1(){
    ....
}

@Transactional
private void transactionalMethod2(Object o){
    ....
}

@Transactional
private void transactionalMethod3(Object o){
    ....
}

If you want to use a single repository just @Autowired a single one and use it in your @Transactional method. E.g:

@Service
@Transactional
public class ServiceImpl1 {

@Autowired
private JPARepository1 repo1; 

public void mainMethod(){
    Object o= transactionalMethod1();

    try{
        transactionalMethod2(o);
    }catch (Exception e){
        transactionalMethod3(o);
    }

}

private Object transactionalMethod1(){
    return repo1.findOne();
}

private void transactionalMethod2(Object o){
    repo1.create(o);
}


private void transactionalMethod3(Object o){
    repo1.delete(o)
}