1.概述
本文将着重于通过对系统中的所有实体使用单个通用的数据访问对象来简化DAO层 ,这将导致优雅的数据访问 ,而不会造成不必要的混乱或冗长。
2. Hibernate和JPA DAO
大多数生产代码库都有某种DAO层。 通常,实现范围从没有抽象基类的多个类到某种通用类。 但是,一件事是一致的- 总是多于一件事-最有可能的是,DAO与系统中的实体之间存在一对一的关系。
同样,根据所涉及泛型的级别,实际的实现方式可能从大量重复的代码变为几乎为空的代码,大部分逻辑分组在基本抽象类中。
通常,可以通过使用Java Generics提供的类型安全性, 用单个参数化DAO替换这些多个实现,这样就不会损失任何功能。
接下来介绍此概念的两种实现 ,一种用于Hibernate中心持久性层,另一种针对JPA 。 这些实现绝不是完整的-仅包括某些数据访问方法,但是可以很容易地使它们变得更彻底。
2.1。 抽象的休眠DAO
public abstract class AbstractHibernateDao< T extends Serializable > {private Class< T > clazz;@AutowiredSessionFactory sessionFactory;public final void setClazz( Class< T > clazzToSet ){this.clazz = clazzToSet;}public T findOne( long id ){return (T) getCurrentSession().get( clazz, id );}public List< T > findAll(){return getCurrentSession().createQuery( "from " + clazz.getName() ).list();}public void create( T entity ){getCurrentSession().persist( entity );}public void update( T entity ){getCurrentSession().merge( entity );}public void delete( T entity ){getCurrentSession().delete( entity );}public void deleteById( long entityId ){T entity = findOne( entityId );delete( entity );}protected final Session getCurrentSession(){return sessionFactory.getCurrentSession();}
}
DAO直接使用Hibernate API,而不依赖于任何Spring模板(例如HibernateTemplate )。 Hibernate DAO教程介绍了模板的使用以及在DAO中自动装配的SessionFactory的管理。
2.2。 通用休眠DAO
现在已经完成了抽象DAO,我们只需实现一次即可- 通用DAO实现将成为唯一需要的实现 :
@Repository
@Scope( BeanDefinition.SCOPE_PROTOTYPE )
public class GenericHibernateDao< T extends Serializable >extends AbstractHibernateDao< T > implements IGenericDao< T >{//
}
首先,请注意,通用实现本身是参数化的 -允许客户根据具体情况选择正确的参数。 这将意味着客户端将获得类型安全的所有好处,而无需为每个实体创建多个工件。
其次,注意这些通用DAO实现的原型范围 。 使用此范围意味着Spring容器将在每次请求DAO时(包括自动装配时)创建一个新的DAO实例。 这将允许服务根据需要将具有不同参数的多个DAO用于不同的实体。
这个作用域如此重要的原因是由于Spring初始化容器中bean的方式。 将通用DAO保留为没有作用域将意味着使用默认的singleton作用域 ,这将导致DAO的单个实例位于容器中。 对于任何一种更复杂的情况,这显然都是主要的限制。
IGenericDao只是所有DAO方法的接口,因此我们可以将Spring的实现注入(或任何需要的)中:
public interface IGenericDao<T extends Serializable> {T findOne(final long id);List<T> findAll();void create(final T entity);T update(final T entity);void delete(final T entity);void deleteById(final long entityId);
}
2.3。 JPA DAO摘要
public abstract class AbstractJpaDao< T extends Serializable > {private Class< T > clazz;@PersistenceContextEntityManager entityManager;public void setClazz( Class< T > clazzToSet ){this.clazz = clazzToSet;}public T findOne( Long id ){return entityManager.find( clazz, id );}public List< T > findAll(){return entityManager.createQuery( "from " + clazz.getName() ).getResultList();}public void save( T entity ){entityManager.persist( entity );}public void update( T entity ){entityManager.merge( entity );}public void delete( T entity ){entityManager.remove( entity );}public void deleteById( Long entityId ){T entity = getById( entityId );delete( entity );}
}
与Hibernate DAO实现类似,此处直接使用Java Persistence API,再次不依赖于现已弃用的 Spring JpaTemplate 。
2.4。 通用JPA DAO
与Hibernate实现类似,JPA数据访问对象也很简单:
@Repository
@Scope( BeanDefinition.SCOPE_PROTOTYPE )
public class GenericJpaDao< T extends Serializable >extends AbstractJpaDao< T > implements IGenericDao< T >{//
}
3.注入此DAO
现在,Spring将注入一个DAO 。 此外, 类需要指定:
@Service
class FooService implements IFooService{IGenericDao< Foo > dao;@Autowiredpublic void setDao( IGenericDao< Foo > daoToSet ){dao = daoToSet;dao.setClazz( Foo.class );}// ...}
Spring 使用setter注入自动装配新的DAO实例,以便可以使用Class对象自定义实现。 在此之后,DAO已完全参数化,可供服务使用。
当然,还有其他方法可以为DAO指定类-通过反射,甚至以XML。 我偏向于这种简单的解决方案,因为与使用反射相比,其可读性和透明度更高。
4。结论
本文通过提供通用DAO的单个可重用实现,讨论了数据访问层的简化 。 在基于Hibernate和JPA的环境中都介绍了此实现。 结果是简化了的持久层,没有不必要的混乱。
有关使用基于Java的配置和项目的基本Maven pom设置Spring上下文的分步介绍,请参阅本文 。
翻译自: https://www.javacodegeeks.com/2011/12/simplifying-data-access-layer-with.html