First off, whether you should use a DAO layer or not is a debate that has been around since the appearance of JPA and the EntityManager which many people consider a DAO itself. The answer to this depends on the type of application you are developing, but in most of the cases you will want to:
- Use JPA criteria or custom queries. In this case you probably don't want to mix your business logic with your query creation. This would lead to large methods and would violate the single responsibility principle.
- Reuse your JPA code as much as possible. Say you create a criteria query that retrieves a list of employees whose age is between 40 and 65 and have been working in the company for longer than 10 years. You might want to reuse this type of query somewhere else in your service layer, and if that is the case, having it in a service would make this task difficult.
That being said, if all you have in your application is CRUD operations and you don't think you might need to reuse any JPA code, a DAO layer is probably something overkill as it will act as a mere wrapper of the EntityManager, which doesn't sound right.
Secondly, I would advise to use container managed transactions whenever possible. In case you are using an EJB container like TomEE or JBoss this would avoid a large amount of code dedicated to programmatically create and manage transactions.
In the case you are using en EJB container, you can take advantage of declarative transaction management. An example of this using DAOs would be to create your service layer components as EJBs and your DAOs too.
@Stateless
public class CustomerService {
@EJB
CustomerDao customerDao;
public Long save(Customer customer) {
// Business logic here
return customerDao.save(customer);
}
}
@Stateless
public class CustomerDao {
@PersistenceContext(unitName = "unit")
EntityManager em;
public Long save(Customer customer) {
em.persist(customer);
return customer.getId();
}
public Customer readCustomer(Long id) {
// Criteria query built here
}
}
In the example above, default transaction configuration is REQUIRED, which means that in absence of a transaction in the caller component, the EJB will create a new transaction. If the caller already creates a transaction (CustomerService) the component being called (CustomerDao) inherits the transaction. This can be customized using the @TransactionAttribute annotation.
If you are not using an EJB container, I think your example above would be probably equivalent.
EDITED: for the sake of simplicity I have used no-interface EJBs above, but it would be a good practice to use an interface for those in order to make them e.g. more testable.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…