Which class should be responsible for starting / ending transaction in JPA?

126 views Asked by At

So I have a sample code like this:

package biz.tugay.books10Aug.dao;
/* User: [email protected] Date: 10/08/15 Time: 22:54 */

import biz.tugay.books10Aug.model.Book;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;

public class BookDaoImpl implements BookDao {

    private EntityManager entityManager;

    public BookDaoImpl(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @Override
    public void persist(Book book) {
        EntityTransaction transaction = entityManager.getTransaction();
        transaction.begin();
        entityManager.persist(book);
        transaction.commit();
    }

}

and this is how I unit test it:

package biz.tugay.books10Aug.dao;
/* User: [email protected] Date: 10/08/15 Time: 22:56 */

import biz.tugay.books10Aug.model.Book;
import org.junit.Test;

import javax.persistence.EntityManager;
import java.text.SimpleDateFormat;
import java.util.Calendar;

public class BookDaoImplTest {

    @Test
    public void testPersistNewBook() throws Exception {
        PersistenceUtil.initalizeEntityManagerFactory();
        EntityManager entityManager = PersistenceUtil.getEntityManager();
        BookDao bookDao = new BookDaoImpl(entityManager);
        String isbn = new SimpleDateFormat("HHmmss").format(Calendar.getInstance().getTime());
        Book book = new Book();
        book.setIsbn(isbn);
        book.setName("Just Another Book in the DB, Volume: " + isbn);
        book.setPrice(10);
        book.setPublishDate(Calendar.getInstance().getTime());
        book.setPublisher("002");
        bookDao.persist(book);
    }

}

This all works fine. My question is about OOP.

I decided that BookDaoImpl should not be responsible for getting the EntityManager. It should be the BookService 's responsibility. Why? I a do not know really.

Also, whos responsibility should be to get transaction, begin and commit? Again BookService or BookDao?

2

There are 2 answers

5
bedrin On BEST ANSWER

JPA Transaction should be managed on a service layer. Here's an counterexample: consider you have a find method in your DAO layer:

public Book find(long id) {
      return entityManager.find(Book.class, id);
}

And your Book class owns a collection of pages:

@OneToMany(mappedBy = "book", fetch = LAZY")
private Set<Page> pages;

public Set<Page> getPages() {
    return pages;
}

If the entityManager has a lifecycle within a DAO, the call of getPages() method made from your service layer will result in lazy initialization exception

Of course in each rule there are exceptions, but in general you should manage your transaction on service layer (or repository layer depending on wording). You can even use MANDATORY transaction demarcation attribute in your DAO layer in order to make it mandatory.

2
Stan On

my opinion is it's ok that BookDao knows about EntityManager since it's about way of data persistence. Regarding transaction - it's responsibility of service layer since it;s responsible for business logic implementation and transaction borders defines in business requirements. However it would be great to implement transaction management independently from persistence technology (now you are using JPA, tomorrow JDBC, later something else). Think Spring's transactions annotations could be a good example of this approach.