当你偶然路过这里时,我假定你已经很明白
				
				
				java
				
				
				中范型和
				
				
				DAO
				
				
				模式了。当然,我也会顺便唠叨几句范型和
				
				
				DAO
				
				
				模式,只是它们不会这篇随笔的重点。我早先在
				
				
				DW
				
				
				上看到一篇蛮不错的文章
				
						
								
										不要重复
								 DAO!Hibernate 和 Spring AOP 构建泛型类型安全的 DAO
				
				,它也促使我在一个实验工程中使用了范型化的
				
				
				DAO
				
				
				模式。前几天看到的另一篇文章
				
						Generic Data Access Objects
				
				使我重新想起了这档事。以前的代码不可追,索性就重做了一个
				
				
				sample
				
				
				实现范型化的
				
				
				DAO
				
				
				。坦白的讲,和上面的两篇文章相比,这篇随笔并没有太多新内容,如果你愿意的话,你可以只看上面的两篇文章而关掉这个页面。
		
		
				先说说范型。自从
				 java5 
				引入范型后,它就成为我代码中不可少的一部分。在没有范型以前,强制转换充斥于文件的各个角落,不单代码不易于阅读,时不时的会出现转换异常。就像你所经历的,对于集合类中的对象,如果显示声明的话,安全性和阅读性都大大提高。总之啦,范型是个很有用的东西。
				
				
		
		
				       
				再说说
				 DAO 
				模式。
				 Java EE 
				中,最经典的架构模式就是三层架构或多层架构。而数据持久化层,流行的就是
				 DAO 
				模式。尽管很多人批评这种
				“
				贫血模型
				”
				不
				 OO 
				,但使用上的方便使得
				 DAO 
				模式很受程序员喜爱。想一想
				 Spring 
				框架吧,支持
				 DAO 
				模式的典型框架,数据与操作的分离,使得
				 IOC 
				、
				 AOP 
				等技术灵活的运转起来。说到底,理论和实践并不是完全统一的,为了满足实际的需要,有时不得不做些折衷。
				
				
		
		
				好了,该说说我做的一个小例子。其实范型化的
				 DAO 
				就是给出一个抽象的
				 DAO 
				及其实现,实现的内容就是基本的
				 CRUD 
				操作。闲言少叙,开始我的代码。
		
		
				范型的
				 DAO 
				接口,包含基本的
				 CRUD 
				操作。
				GenericDAO
				
				
				的实现,通过
				Spring
				
				
				模板实现了
				CRUD
				
				
				操作。
		
		
				
				import
				 java.util.
				*
				;
				import
				 java.io.
				*
				;


				public
				 
				interface
				 GenericDAO
				<
				T, PK 
				extends
				 Serializable
				>
				 
				
						
				
				
						{

    T findById(PK id
						
						
						);

    List
						<
						T
						>
						 findAll();

    
						void
						 insert(T entity);
    
    
						void
						 update(T entity);

    
						void
						 delete(T entity);
}
				
		       
 package org.prague.dao.hibernate;

import java.util.*;
import java.io.*;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.prague.dao.GenericDAO;
import java.lang.reflect.*;

public abstract class GenericHibernateDAO<T, PK extends Serializable>

        implements GenericDAO<T, PK> 
{

    private HibernateTemplate hibernateTemplate;
    private Class<T> type;
    

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

    public void setSessionFactory(SessionFactory sessionFactory)
{
        this.hibernateTemplate = new HibernateTemplate(sessionFactory);
    }
    

    public void delete(T entity) 
{
        this.hibernateTemplate.delete(entity);
    }
    
    


    public List<T> findAll() 
{
        String hql = "from "+this.type.getSimpleName();
        return (List<T>)this.hibernateTemplate.find(hql);
    }


    public T findById(PK id) 
{
        return (T)this.hibernateTemplate.get(type, id);
    }


    public void insert(T entity) 
{
        this.hibernateTemplate.save(entity);
    }


    public void update(T entity) 
{
        this.hibernateTemplate.update(entity);
    }
    

    protected Session getSession()
{
        return this.hibernateTemplate.getSessionFactory().getCurrentSession();
    }
    

    protected HibernateTemplate getHibernateTemplate()
{
        return this.hibernateTemplate;
    }
    
}       
如果不用Spring的话,Hibernate也能轻松的实现这些操作。但坦白的讲,这些操作并不实用。对于不同的实体,可能不会调用这些操作或是调用的操作不完全相同。比如说,对于查询数据表中的数据列表,可能的情况是要求查询条件中按照某些字段排序。如果想给出一个通用的实现方法,接口中不可避免的要包含查询条件,比如说包含一个Hibernate中的条件查询对象。但这样话,就需要在Service层构造查询条件,还不如直接写个方法来的实在。
   
下面就是一个具体的DAO及实现。
import org.prague.domain.*;


public interface AccountDAO extends GenericDAO<Account,Long>
{
    public Account findByNameAndPwd(String name,String pwd);
}
package org.prague.dao.hibernate;

import java.util.List;

import org.prague.dao.AccountDAO;
import org.prague.domain.Account;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;

public class AccountHibernateDAO extends GenericHibernateDAO<Account,Long> implements

        AccountDAO 
{


    public Account findByNameAndPwd(final String name, final String pwd) 
{
        final String hql  = "from Account where name=:name and pwd=:pwd";

        /**//*
        List<Account> list = (List<Account>)this.getHibernateTemplate().executeFind(new HibernateCallback(){
            public Object doInHibernate(Session s) throws HibernateException, SQLException {
                return s.createQuery(hql).setString("name", name).setString("pwd", pwd).list();
            }
        });
        */
        List<Account> list = (List<Account>)this.getHibernateTemplate().findByNamedParam(hql, 

                new String[]
{"name","pwd"}, new String[]
{name,pwd});

        if(list!=null && !list.isEmpty())
{
            return list.get(0);
        }
        return null;
    }
}       当然少不了实体bean了,尽管它很简单。
package org.prague.domain;

import java.io.Serializable;


public abstract class AbstractDomain<PK extends Serializable>
{
    protected PK id;

    

    public PK getId() 
{
        return id;
    }


    public void setId(PK id) 
{
        this.id = id;
    }

}

package org.prague.domain;


public class Account extends AbstractDomain<Long>
{
    private String name;
    private String pwd;
    

    public String getName() 
{
        return name;
    }

    public void setName(String name) 
{
        this.name = name;
    }

    public String getPwd() 
{
        return pwd;
    }

    public void setPwd(String pwd) 
{
        this.pwd = pwd;
    }
    @Override

    public String toString() 
{
        return "Account: id="+this.id+" name="+this.name+" pwd="+this.pwd+"\n";
    }
    
}       想要程序运行起来,还需要配置文件的作用,这里列出Account对应的Hibernate映射文件和Spring配置文件。由于该Sample没有Service层的概念,因此DAO需要声明性事务的作用。
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="org.prague.domain">
    <class name="Account" table="Account">
        <id name="id" column="id" type="java.lang.Long">
            <generator class="identity"></generator>
        </id>
        <property name="name" column="name"></property>
        <property name="pwd" column="pwd"></property>
    </class>
</hibernate-mapping> 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans default-lazy-init="true">

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="configLocation">
            <value>classpath:hibernate.cfg.xml</value>
        </property>
    </bean>

    <bean name="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory">
            <ref bean="sessionFactory" />
        </property>
    </bean>

    <bean id="baseTransactionProxy"
        class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
        abstract="true">
        <property name="transactionManager" ref="transactionManager" />
        <property name="transactionAttributes">
            <props>
                <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
                <prop key="*">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
    </bean>

    <bean id="accountDAO" parent="baseTransactionProxy">
        <property name="target">
            <bean class="org.prague.dao.hibernate.AccountHibernateDAO">
                <property name="sessionFactory">
                    <ref bean="sessionFactory" />
                </property>
            </bean>
        </property>
    </bean>
</beans>       再多说几句吧。我以前写过一个程序,在GenericDAO中给出了更多的方法,比如:
public List<T> findListBy(String expression);
    public void deleteBy(String expression);
    public void updateBy(String expression);    我的想法和做法是不言而喻的。当时想通过在GenericDAO中声明这样的公共方法,简化DAO中操作。那是我还不是很清楚Hibernate中的Creteria,就实现一个类似于Hibernate Creteria包的东西,通过在Service层中构造Creteria对象并得到一个拼接后的hql语句,然后调用上面的这几个方法。通过上面的几个方法,基本上满足了DAO层的操作。但问题是,我不得不在Service层构建Creteria,Service因此显得臃肿异常,而DAO层就单薄得很。好好的想一想,这样的结果不过是变相的将DAO层和Service层合并了。依我的想法,刻意的追求公共数据库操作并不一定实用。即便是这个例子,如果不使用Hibernate框架,而是使用JDBC、Ibatis等,GenericDAO 中的方法是很难以通用的方式实现的。你不得不做的就是,每个继承自 GenericDAO的DAO,都需要单独的实现基本的CRUD操作。