DAO vs ORM(休眠)模式

时间:2010-10-27 20:10:38

标签: java hibernate design-patterns dao

我在一些文章中读到DAO对于hibernate并不是强制性的,它的实现是“依赖于”,换句话说,我们可以在ORM与DAO模式之间进行选择。

好吧,我们假设我不想使用DAO模式,因此我只使用会话CRUD和hibernate(我的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();
}

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

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

3 个答案:

答案 0 :(得分:75)

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

那就是说,虽然你从未真正需要任何东西,但你应该使用DAO。该模式适用于模块化代码。您将所有持久性逻辑保存在一个位置(分离关注点,对抗漏洞抽象)。您允许自己与应用程序的其余部分分开测试数据访问。并且您允许自己测试与数据访问隔离的应用程序的其余部分(即您可以模拟您的DAO)。

另外,即使实现数据访问很困难,遵循DAO模式也很容易。所以它花费你很少(或没什么),你获得了很多。

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

<强> EDIT2

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

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

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

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

查看以下链接,了解基于容器的交易。

Container-Managed Transactions

Sessions And Transactions

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

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

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

AO vs ORM(hibernate) pattern

(thanx @ daff

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

答案 1 :(得分:30)

让我为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)。

答案 2 :(得分:12)

不,我不认为这是正确的。 ORM是实现DAO的一种方式;你可以选择在没有ORM的情况下做DAO。

你已经倒退了:我认为ORM比DAO重,因为依赖性更大。我可以在没有ORM的情况下直接在JDBC中编写DAO。那个更轻,IMO。

我们是否同意取决于我们如何定义“轻”和“重”。我依赖于依赖 - 在JDK本身之上所需的额外JAR数量。