哪个 class 应该负责在 JPA 中开始/结束事务?
Which class should be responsible for starting / ending transaction in JPA?
所以我有一个这样的示例代码:
package biz.tugay.books10Aug.dao;
/* User: koray@tugay.biz 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();
}
}
这就是我对其进行单元测试的方式:
package biz.tugay.books10Aug.dao;
/* User: koray@tugay.biz 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);
}
}
一切正常。我的问题是关于 OOP。
我决定 BookDaoImpl 不应该负责获取 EntityManager。这应该是 BookService 的责任。为什么?我真的不知道。
此外,谁应该负责获取事务、开始和提交?又是 BookService 还是 BookDao?
JPA 事务应该在服务层上进行管理。这是一个反例:
假设您的 DAO 层中有一个 find
方法:
public Book find(long id) {
return entityManager.find(Book.class, id);
}
并且您的图书 class 拥有一组页面:
@OneToMany(mappedBy = "book", fetch = LAZY")
private Set<Page> pages;
public Set<Page> getPages() {
return pages;
}
如果 entityManager 在 DAO 中有一个生命周期,从您的服务层调用 getPages()
方法将导致延迟初始化异常
当然每个规则都有例外,但通常您应该在服务层(或存储库层,具体取决于措辞)管理您的事务。
您甚至可以在 DAO 层中使用 MANDATORY 事务划分属性以使其成为强制性的。
我认为 BookDao 知道 EntityManager 是可以的,因为它是关于数据持久化的方式。
关于交易——它是服务层的责任,因为它负责业务逻辑的实现和业务需求中定义的交易边界。但是,独立于持久性技术实现事务管理会很棒(现在您正在使用 JPA,明天 JDBC,稍后使用其他内容)。想想 Spring 的交易注释可能是这种方法的一个很好的例子。
所以我有一个这样的示例代码:
package biz.tugay.books10Aug.dao;
/* User: koray@tugay.biz 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();
}
}
这就是我对其进行单元测试的方式:
package biz.tugay.books10Aug.dao;
/* User: koray@tugay.biz 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);
}
}
一切正常。我的问题是关于 OOP。
我决定 BookDaoImpl 不应该负责获取 EntityManager。这应该是 BookService 的责任。为什么?我真的不知道。
此外,谁应该负责获取事务、开始和提交?又是 BookService 还是 BookDao?
JPA 事务应该在服务层上进行管理。这是一个反例:
假设您的 DAO 层中有一个 find
方法:
public Book find(long id) {
return entityManager.find(Book.class, id);
}
并且您的图书 class 拥有一组页面:
@OneToMany(mappedBy = "book", fetch = LAZY")
private Set<Page> pages;
public Set<Page> getPages() {
return pages;
}
如果 entityManager 在 DAO 中有一个生命周期,从您的服务层调用 getPages()
方法将导致延迟初始化异常
当然每个规则都有例外,但通常您应该在服务层(或存储库层,具体取决于措辞)管理您的事务。 您甚至可以在 DAO 层中使用 MANDATORY 事务划分属性以使其成为强制性的。
我认为 BookDao 知道 EntityManager 是可以的,因为它是关于数据持久化的方式。 关于交易——它是服务层的责任,因为它负责业务逻辑的实现和业务需求中定义的交易边界。但是,独立于持久性技术实现事务管理会很棒(现在您正在使用 JPA,明天 JDBC,稍后使用其他内容)。想想 Spring 的交易注释可能是这种方法的一个很好的例子。