JPA的泛型DAO設計及使用


  • 使用如Hibernate或者JPA作為持久化的解決方案時,設計一個泛型的DAO抽象父類可以方便各個實體的通用CRUD操作。由於此時大部分實體DAO的CRUD操作基本一樣,采用泛型設計解決這個問題,帶來了簡潔代碼的好處。
  • 問題的關鍵在於我們需要在代碼中獲取抽象DAO父類(BaseEntityDAOImpl<T>)中的泛型信息。
  • 由於Java的泛型是基於泛型擦除實現的,因此無法直接獲取如果直接獲取,在Java中,如果子類繼承一個泛型的父類,會保存父類中泛型的信息,因此可以采用如下方法獲取泛型信息。
    public abstract class BaseEntityDAOImpl<T> { 
         protected Class<T> entityClass;  
         public  BaseEntityDAOImpl() {
    // 由於Java 方法的動態綁定getClass()調用的是子類方法
    // getGenericSuperclass()返回直接父類的Type類型,並保存了泛型參數的實際類型信息。
    Type genType = getClass().getGenericSuperclass(); Type[] params = ((ParameterizedType)genType).getActualTypeArguments();
       // 獲取實際的泛型參數的類型信息。
    entityClass = (Class<T>) params[0]; }

    }
  • 在獲取了泛型參數實際類型之后,以下使用JPA的EntityManager來對通用CRUD操作實現,如下:
public class BaseEntityDAOImpl<T> {
        protected Class<T> entityClass;
        //@PersistenceContext注解后,entityManager由Spring負責注入
        @PersistenceContext
        protected EntityManager entityManager;
        public  BaseEntityDAOImpl() {  
            Type genType = getClass().getGenericSuperclass();  
            Type[] params = ((ParameterizedType) genType).getActualTypeArguments();  
            entityClass = (Class<T>) params[0];  
        }  

        public EntityManager getEntityManager(){
            return entityManager;
        }
        public void setEntityManager(EntityManager entityManager){
            this.entityManager=entityManager;
        }

        public void add(T t){
            entityManager.persist(t);
        }
        public void update(T t){
            entityManager.merge(t);
        }
        public T getById(long id){
            return entityManager.find(entityClass, id);
        }
        public void deleteById(long id){
            T t=getById(id);
            if(t!=null){
                entityManager.remove(t);
            }
        }
        public void delete(T t){
            entityManager.remove(t);
        }
        
        public List<T> getListByPage(int offset,int maxResult){
            
            return (List<T>)getEntityManager().createQuery("from "+entityClass.getSimpleName()).setFirstResult(offset).setMaxResults(maxResult).getResultList();
        }
        
        public List<T> getAll(){
            return (List<T>)getEntityManager().createQuery("from "+entityClass.getSimpleName()).getResultList();
        }
        


}

 

  • 使用客戶Customer和訂單Order兩個實體的作為例子,我們可以通過繼承泛型的DAO抽象父類來實現實體DAO接口的CRUD,而DAOImpl中沒有相關的代碼,類圖如下:

  • Spring 和JPA集成如下,事務的配置使用注解實現:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="cn.cjtblog.jpatest"/>
    <context:property-placeholder location="classpath:jdbc.properties" />
    <tx:annotation-driven transaction-manager="transactionManager"/>
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}" />
        <property name="url"
            value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
    </bean>
    <!-- 對注解Jpa EntityManager的@PersistenceContext,進行注入 -->
    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="packagesToScan" value="cn.cjtblog.jpatest" />
        <property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
        <property name="jpaDialect" ref="jpaDialect" />
        <property name="persistenceProvider" ref="persistenceProvider" />
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
                <prop key="hibernate.show_sql">false</prop>
                <prop key="hibernate.format_sql">true</prop>
            </props>
        </property>

    </bean>
    <bean id="persistenceProvider" class="org.hibernate.jpa.HibernatePersistenceProvider" />
    <bean id="jpaVendorAdapter"
        class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <property name="database" value="MYSQL" />
        <property name="showSql" value="true" />
    </bean>
    <bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />


    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
        <property name="jpaDialect" ref="jpaDialect" />
    </bean>
</beans>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM