边城愚人

如果我不在边城,我一定是在前往边城的路上。

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  31 随笔 :: 0 文章 :: 96 评论 :: 0 Trackbacks

当你偶然路过这里时,我假定你已经很明白 java 中范型和 DAO 模式了。当然,我也会顺便唠叨几句范型和 DAO 模式,只是它们不会这篇随笔的重点。我早先在 DW 上看到一篇蛮不错的文章 不要重复 DAOHibernate 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层构建CreteriaService因此显得臃肿异常,而DAO层就单薄得很。好好的想一想,这样的结果不过是变相的将DAO层和Service层合并了。依我的想法,刻意的追求公共数据库操作并不一定实用。即便是这个例子,如果不使用Hibernate框架,而是使用JDBCIbatis等,GenericDAO 中的方法是很难以通用的方式实现的。你不得不做的就是,每个继承自 GenericDAODAO,都需要单独的实现基本的CRUD操作。  

 

posted on 2007-04-17 08:55 kafka0102 阅读(3579) 评论(7)  编辑  收藏 所属分类: Pattern

评论

# re: 要范型,要DAO,更要范型DAO[未登录] 2007-04-17 09:07 Matthew
朋友,把排版重搞一下吧!  回复  更多评论
  

# re: 要范型,要DAO,更要范型DAO 2007-04-17 09:20 kafka0102
都要疯掉了。昨晚第一遍写的时候,直接在编辑器里做,结果添加代码框出不来,IE死掉了。第二遍在word里写,结果发表时不能连接服务器。好吧,一大早来做,结果从word到编辑器转换时,格式都乱了。就这样了,没心情再改了。  回复  更多评论
  

# re: 要范型,要DAO,更要范型DAO 2007-04-17 10:32 CrossAge
这样子做,还有必要搞DAO这一层么?
目的就是为了节省CRUD的代码量?  回复  更多评论
  

# re: 要范型,要DAO,更要范型DAO 2007-04-18 08:40 开源英汉机器翻译
开源英汉机器翻译C#.NET项目 www.liebiao.net

我们邀请你 技术交流  回复  更多评论
  

# re: 要范型,要DAO,更要范型DAO[未登录] 2007-04-27 13:20 Diego
楼主,你博客上的的代码折叠功能是用什么工具生成的?我问了好几个人都不知道,我也想要这个功能  回复  更多评论
  

# re: 要范型,要DAO,更要范型DAO 2007-05-03 22:06 kafka0102
发表文章时,代码不是直接贴进去的,而是选择编辑器中的“代码”选项(应该在编辑菜单的最后一个位置),然后根据弹出来的对话框进行操作就行了。  回复  更多评论
  

# re: 要范型,要DAO,更要范型DAO 2008-10-31 11:14 天山剑
需要一个范型dao,

上面的有问题,测试不了

有没有测通的

请高手指点

QQ:328152797

  回复  更多评论
  


只有注册用户登录后才能发表评论。


网站导航: