【问题标题】:Generic DAO with Hibernate and Spring, is their a better way than this?带有 Hibernate 和 Spring 的通用 DAO,是比这更好的方法吗?
【发布时间】:2012-03-07 00:14:51
【问题描述】:
public class GenericDao <T, PK extends Serializable> {

    private final Class<T> type;

    @Resource(name = "sessionFactory")
    private SessionFactory sessionFactory;

    public GenericDao(final Class<T> type) {
    this.type = type;
    }

    public PK save(final T o) {
    return (PK) sessionFactory.getCurrentSession().save(o);
    }
// ... get,delete, etc

应用上下文 bean:

<bean id="fooDao" class="com.mycompany.dao.GenericDao">
        <constructor-arg>
            <value>com.mycompany.Foo</value>
        </constructor-arg>
    </bean>

在服务层调用如下:

@Autowired
private GenericDao<Foo, Integer> fooDao;
...
public doStuffIncludingSave(Foo foo)
fooDao.save(foo);

【问题讨论】:

  • @soulcheck 在任何意义上都更好。例如,是否有我遗漏的最佳实践立场实践。我是否必须通过 xml 传递构造函数参数,是否适合泛型,这是它们的内置弹簧机制。

标签: java hibernate spring dependency-injection dao


【解决方案1】:

一个好的起点是Generic DAO article,它来自 2006 年,但其中包含一些很好的信息。为了更新 Spring、hibernate 和 annotations 的通用 DAO,这就是我所做的。这个newer article 也很有用。

所有标识符都是通用接口,以确保类具有I getId() 和setId(I id)

创建通用 DAO 接口

public interface GenericDao<T extends Identifier<I>, I extends Serializable> {
    public T find(I id);
    public void delete(T obj);
    public void saveOrUpdate(T obj);
}

创建您的 GenericDAO 实施

public abstract class GenericDaoImpl<T extends Identifier<I>, I extends Serializable> implements GenericDao<T, I>{

    private Class<T> type;

    @Autowired
    private SessionFactory sessionFactory;
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
    protected SessionFactory getSessionFactory() {
        if (sessionFactory == null)
            throw new IllegalStateException("SessionFactory has not been set on DAO before usage");
        return sessionFactory;
    }

    public Class<T> getType() {
        return type;
    }

    public GenericDaoImpl() {
        this.type = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

    @Transactional(readOnly = true)
    @Override
    public T find(I id) {
        return (T) getSessionFactory().getCurrentSession().get(getType(), id);
    }

    @Transactional
    @Override
    public void delete(T obj) {
        getSessionFactory().getCurrentSession().delete(obj);
    }

    @Transactional
    @Override
    public void saveOrUpdate(T obj) {
        getSessionFactory().getCurrentSession().saveOrUpdate(obj);
    }
}

对象DAO接口:

public interface SomeObjectDao extends GenericDao<SomeObject, Long>{
}

对象 DAO 实现

@Repository
public class SomeObjectDaoImpl extends GenericDaoImpl<SomeObject, Long> implements SomeObjectDao {

}

现在在任何需要它的类中,比如服务类,你可以通过添加你需要的对象类 dao 来实现自动装配

@Autowired
private SomeObjectDao someObjectDao;

【讨论】:

  • 你的标识符是哪个类?例如org.springframework.expression.spel.ast.Identifier 或 org.hibernate.metamodel.relational.Identifier。无论哪种方式,我都会收到编译错误消息:“标识符不接受参数”
  • 我用的也不是,自己做的:public interface Identifier&lt;I extends Serializable&gt; { I getId(); void setId(I identifier); }
  • 改变有用的答案@Sebastien
  • 这个实现没有Service接口和实现。要让它在没有同步错误的情况下工作,请确保将 Configuration 类中的@EnableTransactionManagement 更改为@EnableTransactionManagement(proxyTargetClass=true)。然后将@Transactional注解移动到Service Implementation类而不是已经用@Repository注解的DaoImpl类
【解决方案2】:

我认为您的解决方案很好,但您不需要类参数T。它只是限制您并且不允许将相同的 DAO 用于整数和字符串(例如)。

Save 方法根本不需要这种类型。

get() 或 find() 等方法本身应该接收泛型类型:

public &lt;T&gt; T findById(Class&lt;T&gt; clazz, Serializable id);

public &lt;T&gt; List&lt;T&gt; listAll( Class&lt;T&gt; clazz );

【讨论】:

  • 然后我可以删除构造函数参数并使用相同的实现来查找/删除任何类型?
  • 我将如何调用依赖注入?
【解决方案3】:

比自己写更好用

两者看起来非常相似:只有界面,没有实现:

public interface UserDao extends GenericDao<User, Long> {
     User findByLogin(String login);         
}

如果您有兴趣,请查看文档。

【讨论】:

  • 它们中的任何一个会是什么样子?
  • 如果能简短解释一下它的作用就好了?
【解决方案4】:

看起来您正在将类型传递给 dao,这样您就可以获得 dao 中泛型的正确类型。您可以使用Spring's java configuration 而不是这样做,这将允许您拥有类似以下的方法:

@Bean(name="myAsdfDao")
public GenericDao<MyAsdf, MyAsdfId> getMyAsdfDao() {
    return new GenericDao<MyAsdf, MyAsdfId>();
}

这将让您保留特定于实体的 daos,而无需通过 xml 配置将类型传递给构造函数。这将在一个为 spring 提供基于 java 的配置的 @Configuration 注释类中。

【讨论】:

  • 啊哈,所以我会为每个实体类型(foo、bar 等)在类上使用不同的方法。
【解决方案5】:

这种设计的缺点——你会做什么来执行一些重要的操作?那么对许多对象的操作呢?当请求中使用的对象数量达到相当大的数量(例如 1000 个)时,由于多个数据库请求,您将面临极大的减速。

根据我的经验,它创建一些类(如提供的 GenericDao)然后从中派生特定 DAO 的好方法。它允许在 GenericDao 中放置一些有用的常用方法,并在特定的派生类中实现特定的方法。

【讨论】:

    猜你喜欢
    • 2011-04-22
    • 2013-06-07
    • 2018-01-10
    • 1970-01-01
    • 2013-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多