DAO 与 ORM(休眠)模式 [已关闭]

2022-08-31 21:09:38

我在一些文章中读到,DAO不是强制性的,休眠,它的实现是通过“它取决于”,换句话说,我们可以在ORM与DAO模式之间进行选择。

好吧,让我们假设我不想使用DAO模式,所以我只使用会话CRUD和休眠(我的ORM)提供的查询操作。

特别是对于“搜索”和“查找”查询,总是重写它们是不正确的,所以合理地认为把它们放到一个类中。

但是这个类是一个简单的DAO,没有DAO模式和DAOFactory的所有实现,只是一个DAO的轻量级实现。所以,关键是我们需要一个DAO,选择是重DAO实现还是轻量级DAO实现?

我说的不对劲?

编辑我遇到的另一个问题是把dao交互放在哪里,例如我必须登录用户并编写登录日志(我知道的无用的例子...)

因此,在DAO模式中,我拥有所有通用的Dao实现,DAOFactory,最后是UserHibernateDAO和LogHibernateDAO。登录操作是一种业务方法

private void login(String username, String password){
    daoFactory.beginTransaction();
    UserDAO userDao=daoFactory.HIBERNATE.getUserDao();
    LogDAO logDao=daoFactory.HIBERNATE.getLogDao();
    if(userDao.checkAccount(username, password){
        User user=userDao.findByAccount(username, password);
        logDao.save(new Log("log-in", user);
    }
    daoFactory.commit();
}

这合理吗?我可以以这种方式使用道吗?如果我想处理异常,更好的地方是 ina 业务逻辑?

编辑2让我们假设使用DAO模式,这样做的主要原因是能够在tecnhology(ORM->JDBC等)之间切换,这一切都很好,但是我在哪里可以处理休眠会话和事务?我不能把它放到一个DAO中,它是anty模式,我不能把它放到一个服务层中,在一个hipohtycal开关中,我必须删除所有这些事务(becouse其他技术可能不使用它们)。


答案 1

ORM 和 DAO 是正交概念。一个与如何将对象映射到数据库表有关,另一个是用于编写访问数据的对象的设计模式。您不会在它们之间进行选择。你可以有ORM和DAO是同一个应用程序,就像你不需要ORM来使用DAO模式一样。

也就是说,虽然你从来没有真正需要任何东西,但你应该使用DAO。该模式适用于模块化代码。你把所有的持久性逻辑都放在一个地方(分离关注点,反对泄漏的抽象)。您可以允许自己独立于应用程序的其余部分测试数据访问。您可以允许自己测试与数据访问隔离的应用程序的其余部分(即,您可以模拟您的DAO)。

此外,遵循 DAO 模式很容易,即使实现数据访问可能很困难。因此,它花费您很少(或什么都没有),并且您获得了很多。

编辑 --对于您的示例,您的登录方法应该在某种身份验证服务中。您可以在那里处理异常(在登录方法中)。如果你使用Spring,它可以为你管理一堆事情:(1)事务,(2)依赖注入。您不需要编写自己的事务或 dao 工厂,只需围绕服务方法定义事务边界,并将 DAO 实现定义为 bean,然后将其连接到服务中即可。

编辑2

使用该模式的主要原因是将关注点分开。这意味着您的所有持久性代码都在一个地方。这样做的副作用是,可测试性和可维护性,以及这使得以后切换实现变得更加容易。如果你正在构建基于Hibernate的DAO,你绝对可以在DAO中操纵会话,这是你应该做的。反模式是指与持久性相关的代码发生在持久性层之外(泄漏抽象定律)。

交易有点棘手。乍一看,交易似乎是一个持久性的问题,事实也确实如此。但它们不仅是对持久性的关注。事务也是服务关注的问题,因为你的服务方法应该定义一个“工作单元”,这意味着,服务方法中发生的所有事情都应该是原子的。如果您使用休眠事务,那么您将不得不在DAO之外编写休眠事务代码,以定义使用许多DAO方法的服务周围的事务边界。

但请注意,事务可以独立于您的实现 - 无论您是否使用休眠,您都需要事务。另请注意,您不需要使用休眠事务机制 - 您可以使用基于容器的事务,JTA事务等。

毫无疑问,如果你不使用Spring或类似的东西,交易将是一个痛苦。我强烈建议使用Spring来管理您的事务,或者使用EJB规范,我相信您可以使用注释来定义围绕服务的事务。

查看以下链接,了解基于容器的事务。

容器管理的事务

会话和事务

我从中收集到的是,您可以在服务级别轻松定义DAO外部的事务,并且不需要编写任何事务代码。

另一种(不太优雅的)替代方案是将所有原子工作单元放在DAO中。您可以为简单操作提供 CRUD DAO,然后使用更复杂的 DAO 执行多个 CRUD 操作。这样,您的程序化事务将保留在 DAO 中,并且您的服务将调用更复杂的 DAO,并且不必担心事务。

以下链接是 DAO 模式如何帮助您简化代码的一个很好的例子

AO 与 ORM(休眠)模式

(感恩节@达夫)

请注意接口的定义是如何使业务逻辑只关心 UserDao 的行为。它不关心实现。你可以使用休眠来编写一个DAO,或者只是JDBC。因此,您可以更改数据访问实现,而不会影响程序的其余部分。


答案 2

让我提供一个源代码示例来hvgotcodes好答案:

public class Application
{
    private UserDao userDao;

    public Application(UserDao dao)
    {
        // Get the actual implementation
        // e.g. through dependency injection
        this.userDao = dao;
    }

    public void login()
    {
        // No matter from where
        User = userDao.findByUsername("Dummy");
    }
}


public interface UserDao
{
    User findByUsername(String name);
}

public class HibernateUserDao implements UserDao
{
    public User findByUsername(String name)
    {
        // Do some Hibernate specific stuff
        this.session.createQuery...
    }
}

public class SqlUserDao implements UserDao
{
    public User findByUsername(String name)
    {
        String query = "SELECT * FROM users WHERE name = '" + name + "'";
        // Execute SQL query and do mapping to the object
    }
}

public class LdapUserDao implements UserDao
{
    public User findByUsername(String name)
    {
        // Get this from LDAP directory
    }
}

public class NoSqlUserDao implements UserDao
{
    public User findByUsername(String name)
    {
        // Do something with e.g. couchdb
        ViewResults resultAdHoc = db.adhoc("function (doc) { if (doc.name=='" + name + "') { return doc; }}");
        // Map the result document to user
    }
}

因此,如前所述,DAO是一种设计模式,用于最大限度地减少应用程序和后端之间的耦合,而ORM处理如何将对象映射到对象关系数据库(这减少了数据库和应用程序之间的耦合,但最终,如果不使用DAO,您的应用程序将依赖于所使用的ORM或更高级别的标准,如JPA)。

因此,如果没有DAO,就很难更改您的应用程序(例如,移动到NoSQL数据库而不是与JPA兼容的ORM)。


推荐