我在一些文章中读到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开关我必须删除所有这个交易(因为其他技术可能不会使用它们)。
答案 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
我从中收集到的是,您可以在服务级别轻松定义DAO之外的事务,而无需编写任何事务代码。
另一种(不太优雅)的替代方案是将所有原子单位放在DAO中。您可以使用CRUD DAO进行简单操作,然后使用更复杂的DAO执行多个CRUD操作。这样,您的程序化事务将保留在DAO中,您的服务将调用更复杂的DAO,而不必担心事务。
以下链接是DAO模式如何帮助您简化代码的一个很好的示例
(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数量。