DAO和Service层与Hibernate的结合

4
我在服务层的实现中遇到了麻烦,我想我没有很好地理解这个概念。
在DAO的实现中,我可以为特定的技术和实体(例如Hibernate和User表)编写所有CRUD逻辑,在服务层中,我们使用DAO来进行DAO中实体的所有数据操作(如getUser、loginUser等)。这样做可以吗?
如果可以,我有一个简单的问题,我可以在服务层或DAO实现中处理数据库连接(或在Hibernate的情况下,会话和事务),还是两者都不可以?
例如,我有一个简单的GUI,其中包含一个按钮(加载所有用户),以及一个包含所有用户的表格。按下按钮将使用所有用户加载表格。
我有一个用于User实体的HibernateDAO(UserHibernateDAO),包含所有CRUD操作,以及一个UserService的服务层,用于一些特定的用户数据操作。
服务层:
public class UserService extends AbstractServiceLayer{

    private AbstractDAO dao;

    public UserService(AbstractDAO dao){
     this.dao=dao;
    }

    public List<User> loadAllUsers(){
     return dao.findAll();
    }

}

在按钮的ActionPerformed中:
private void buttonActionPerformed(ActionEvent evt) {
    Transaction transaction=HibernateUtil.getSessionFactory().getCurrentSession().beginTransaction();
    List<User> users=userService.loadAllUsers();
    loadTableWithUsers(users);
    transaction.commit();
}

这个实现可以吗?会话和事务处理的位置是否正确,还是我需要将它放到服务层中?...或者放到数据访问对象(DAO)中?
编辑1: 如果我有一个UserDAO接口和一个实现UserDAO的UserHibernateDAO,那么服务层就没有存在的理由了,对吗?因为我可以在我的UserDAO中拥有管理“USER”的所有方法,而UserHibernateDAO为Hibernate技术实现了所有这些方法...然后我可以有一个UserJdbcDAO、UserMysqlDAO等...
编辑2:
private void buttonActionPerformed(ActionEvent evt) {
    myBusinessMethod();
}

private void myBusinessMethod(){
    Transaction transaction=HibernateUtil.getSessionFactory().getCurrentSession().beginTransaction();
    List<User> users=userService.loadAllUsers();
    loadTableWithUsers(users);
    //some other useful operation before close session
    transaction.commit();
}

我不确定,“商业方法”是指这样的方法吗?
谢谢大家。

我想,我已经回答了你的“编辑”:)。请看我的第二个建议。 - Adeel Ansari
1个回答

5
您正在actionPerformed()方法中处理事务,这显然违背了DAO/Service层的目的。
您的UserService接受AbstractDAO,这意味着其他代码可能会将错误的DAO实现传递给您的UserService,从而使事情变得混乱。
现在,提出几点建议。
您可以查看此GenericDAO概念。那可能符合您的需求。
大多数时候,我们不需要像ServiceDAOBusinessDelegate这样的所有层。因此,要问自己这些是否真正回答了您的一些问题。如果没有,就摆脱它们。YAGNI 完全摆脱DAO,并将Hibernate API视为DAO。在您的业务方法中处理数据库事务。您可能想阅读此问题
[编辑]
在您的编辑后,我的第三个建议并没有太大分量。顺便说一下,您的DAO名称如下:UserJdbcDAOUserMysqlDAO等。您的第二个名称没有太多意义,因为我们使用ORM仅为了避免DB供应商特定的DAO/查询。如果您的UserMysqlDAO extends UserJdbcDAO,它可能开始有些意义。

@blow:你可以在DAO或业务方法中处理它。我通常更喜欢在我的业务方法中处理它。 - Adeel Ansari
@blow:哦,好的。既然你正在保留你的DAO,那么在DAO方法中管理事务就没问题了。也许,唯一的问题是当你在调用代码中需要加载一些配置为“fetch-lazy”的关联时,会遇到问题。为什么呢?因为你的会话已经关闭,你不能再向数据库发出请求了。 - Adeel Ansari
@blow:你是如何在DAO中获取会话的?顺便说一下,你在actionPerformed()中也要求会话。你不觉得你正在两次请求会话吗? - Adeel Ansari
@Adeel Ansari:在我的DAO中,我简单地通过HibernateUtil.getSessionFactory().getCurrentSession()获取会话,但从未开始事务或提交它。是的,它被获取了两次,但由Hibernate管理,所以当前会话是相同的会话。 附注:我已编辑了我的问题,我的示例是业务方法吗? 再次感谢。 - blow
1
@blow:是的,很可能会是同一个会话。但看起来不太整洁。现在第二个问题,是的,可以说是业务方法,确切地说。 - Adeel Ansari
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接