简体   繁体   English

使用Hibernate和Spring的通用DAO是他们比这更好的方法吗?

[英]Generic DAO with Hibernate and Spring, is their a better way than this?

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

App context bean: App上下文bean:

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

And in service layer invoke like so : 并在服务层调用如下:

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

A good place to start is this Generic DAO article its from 2006 but has some good information in it. 一个好的起点是这篇Generic DAO文章,它来自2006年,但它有一些很好的信息。 To update the generic DAO for Spring, hibernate and annotations this is what I have done. 要更新Spring的常规DAO,hibernate和注释,这就是我所做的。 Also this newer article is quite useful as well. 这篇新文章也很有用。

All identifier is is a generic intferface to make sure the class has a I getId() and setId(I id) 所有标识符都是一个通用的接口,以确保该类具有I getId()setId(I id)

Create a Generic DAO interface 创建通用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);
}

Create your GenericDAO Implementation 创建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);
    }
}

Object DAO interface: 对象DAO接口:

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

Object DAO implementation 对象DAO实现

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

}

now in Any class that needs it, like a service class, you can get autowiring by just adding the object class dao that you need 现在在需要它的任何类中,就像服务类一样,你可以通过添加你需要的对象类dao来获得自动装配

@Autowired
private SomeObjectDao someObjectDao;

I think your solution is fine but you do not need the class parameter T . 我认为您的解决方案很好,但您不需要类参数T It just limits you and does not allow to re-use the same DAO for Integers and Strings (for example). 它只是限制你,并且不允许为整数和字符串重复使用相同的DAO(例如)。

Save method does not need this type at all. Save方法根本不需要这种类型。

Methods like get() or find() should receive generic type themselves: get()find()应该自己接收泛型类型:

public <T> T findById(Class<T> clazz, Serializable id);

public <T> List<T> listAll( Class<T> clazz );

Better than writing it by yourself would be using 比自己写的更好用

In both it will look very similar: only the interface, no Implmentation: 在两者中它看起来都非常相似:只有界面,没有Implmentation:

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

If you are interested in, look at the documentation. 如果您有兴趣,请查看文档。

It looks like you are passing the type to the dao just so you can get the correct type for the generics in the dao. 看起来你正在将类型传递给dao,这样你就可以为dao中的泛型获得正确的类型。 Rather than do that you could use Spring's java configuration which would allow you to have a method something like: 您可以使用Spring的java配置 ,而不是这样做,这将允许您使用类似的方法:

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

which would let you keep entity specific daos without having to pass the type to a constructor through xml config. 这将让你保持实体特定的daos,而不必通过xml配置将类型传递给构造函数。 This would be in an @Configuration annotated class that provides java based configuration for spring. 这将在一个@Configuration注释类中,为spring提供基于java的配置。

The bad point of such design -- what would you do to perform some non-trivial actions? 这种设计的不好之处 - 你会做些什么来执行一些非平凡的行动? And what about actions on many object? 对许多对象的行为怎么样? When the number of objects used in request will reach some significant amount (say, 1000) you will face a great slowdown due to multiple db requests. 当请求中使用的对象数量达到一定数量(例如1000)时,由于多个数据库请求,您将面临极大的减速。

From my experience the good way it to create some class like presented GenericDao and then derive particular DAO's from it. 根据我的经验,创建一些类的好方法就像GenericDao一样,然后从中派生出特定的DAO。 It allows to put some useful common methods in GenericDao and implement specific methods in particular derivatives. 它允许在GenericDao中放入一些有用的常用方法,并在特定的衍生物中实现特定的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM