论坛首页 Java企业应用论坛

关于DAO层的疑惑!!!平地一声雷

浏览 24790 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (14) :: 隐藏帖 (6)
作者 正文
   发表时间:2011-08-03  
DAO的终极目标是DAL,也就是说只有真正需要经历数据量历练的项目,DAO才是必须
0 请登录后投票
   发表时间:2011-08-03  
每个实体类提供一个DAO 继承 BaseDAO,一些基本的操作 都放在 BaseDAO 里面
0 请登录后投票
   发表时间:2011-08-03  
DAO的设计和使用与Service, Action等层次是密不可分的,因此在讨论这个问题时,我们是不是应该讨论清楚3者间的职能划分。

我见过有人这样设计和使用过:

一、Action, Service, DAO皆有,Service与DAO里的方法一一对应,大部分的逻辑处理都在DAO里面完成(许多的SQL语句),而Service则是一行调用DAO对应方法的代码。

二、觉得DAO多余,就把DAO和Service合并了(以前我就这么干过)

三、条件多点的查询,查询条件(HQL, 或SQL)从页面或Action传过来

四、Action直接调用DAO

五、一个复合的业务操作(需要由多个步骤完成),都在一个DAO中实现了

六、数据库事务放Action, Service, DAO(放哪里的都有)


总之没能合理划分3者职责的情况非常普遍,这个问题是Action, Service, DAO职能划分的问题,主要也是Service, 与DAO的职能划分。

我是这么认为的:
Service的语义是业务上的,存在于Service中的方法应该是如:
    创建用户账号,
    增加账户余额,
    用户操作违规扣除积分,
    。。。

DAO中的语义则是针对数据库的,存在于其中的方法就应该说成:
     创建user记录
     更新account表中balance的值
     更新user_score中score的值
     加载user实体
     加载account实体
     加载user_score实体
    。。。

以上的DAO方法都应是最简单的,一般都可以通过一条“简单”的SQL语句完成,如果SQL语句很复杂可能有2种情况:1)业务确实复杂,通常是查询;2)DAO方法的职责不是单一的。我们应该尽量实现单一功能的DAO方法,尽量让SQL语句简单。

Service中的内容应该是复合的,简单的CRUD那也没什么说的,想怎么就怎么吧。
逻辑稍微复杂点的功能都是可以划分成步骤的,比如对增加账户余额的功能,对应service中的方法可以是这样的
1)加载用户实体
2)用户存在,然后找到账户实体
3)验证账户余额,
4)增加或减少账户余额

上面4个方法都对应着DAO中的一个方法。



通常的业务性操作都是可以总结出这样的方法的,但也不排除一些特有操作,这个操作很不通用,就是在某一个地方使用的,根本没法复用。这可能是由于业务研究不透彻,设计不明确照成的,这很正常,因为没有足够的时间去好好推敲方法的设计吗。还有就是各种各样,五花八门的查询。

对于查询,我是没办法,干脆就一个查询一个DAO方法,参数都包含在MAP里,SERVICE里别包含SQL, HQL(HQL和SQL不都是不能垮平台、跨系统的障碍吗)。

不能闲麻烦,就是多几个配置文件吗,一个人用几天就都写完了,累是累点,但那不算是问题。真正耗费时间的是在关键代码书写上和BUG调试上。


DAO还是有存在的道理(如果只用一个通用类,那么JdbcTemplate就可以了), Service, DAO, Action3者到底应该放置什么样的代码,他们的职能划分才是关键
0 请登录后投票
   发表时间:2011-08-03  
feiyang404 写道
魔力猫咪 写道
我目前对Dao的设计考虑是这样的。
使用ORM框架,设计一个只有基本CRUD的Dao接口。
public interface BaseDao<T> {
	public void perser(T t);
	public void mager(T t);
	public void delete(T t);
	public T find(Object id);
}

大概是这个样子。然后写一个实现,用来实现基本的CRUD操作。
针对每个对象的专有Dao接口,是在继承BaseDao的基础上完成的。例如:
public interface ADao<T> extends BaseDao {
	public List<T> findAll();
	public List<T> findByXXX(Map params);
}

然后这个专有Dao的实现是组合了基本BaseDao实现的。对基本CRUD进行代理,并实现自己的专有方法。
public class ADaoImpl implements ADao {
	
	private BaseDao bDao;
	
	public void delete(Object t) {
		bDao.delete(t);
	}

	public Object find(Object id) {
		return bDao.find(id);
	}

	public void mager(Object t) {
		bDao.mager(t);
	}

	public void perser(Object t) {
		bDao.perser(t);
	}

	public List findAll() {
		...
	}

	public List findByXXX(Map params) {
		...
	}
}


像你这种写法,我想过,xml文件中的配置会配很多xxxDao;然后每个dao引用sessionfactory,这样到不如写一个通用dao然后再service层传过来hql语句,毕竟写一个hql比写一个Dao类来的方便多了.

我考虑良久,觉得不能太钻牛角尖了,所以,不能说dao层只能提供数据持久化,而应该说dao和service层共同负责提供数据业务处理接口,而Action层才是真正的业务逻辑,需要换持久化框架的时候,改写dao和service层这两个整体.

不知道我这种想法是否合理?

我后面还有话的。如果能够实现语句配置存储,那么Dao就可以精简到1个。这个我前面忘说了。除了持久化模块外,我认为任何其他地方出现数据库处理都是违规的。会造成模块结构混乱和框架紧耦合。
所谓的Action层其实只是负责接收客户端请求的,在Seam这样的框架中甚至都被去掉了。在其中写业务,那么就表示事务AOP必须切到表现层,现有的MVC框架恐怕无法无缝直接支持事务。
0 请登录后投票
   发表时间:2011-08-03  
我觉得形如这样挺好的:

List<T> list=CommonJdgcDao.query(sql,T.class);

T t=CommonJdgcDao.get(sql,T.class);

List<T> list=CommonHibernateDao.query(hql);

T t=CommonHibernateDao.get(sql);

T t=CommonHibernateDao.load(T.class,id);

CommonHibernateDao.save(t);

CommonHibernateDao.update(t);

CommonHibernateDao.delete(t);

两个通用的DAO工具类,泛型+反射。
0 请登录后投票
   发表时间:2011-08-03  
feiyang404 写道

我个人认为,dao层只应提供数据持久化接口,和数据库,Service层均没有关系,如果持久化框架变了,比如不用Hibernate,而改用ibatIS,那么只需要将DAO里面的实现稍作改动,整个系统就可以流畅运行.所以,这就要求在Service层不要写HQL或者QBC,Service层专注调用DAO层接口为Action层提供服务,和DAO层无耦合.这样如果写一个通用DAO层的话,就会提高代码重用性,并且xml配置也很简洁,只要配置一个通用的dao就可以了,但是却使以牺牲灵活性为前提的,比如在Service层需要一个按属性查询的方法,那么在DAO层就要写where子句(where xxx=yyy),但是通用dao不可能知道xxx,怎么办呢?

 

如果通用DAO层接受Service层传来的HQL的话,那就会很容易写出一个灵活性高,重用性强的DAO通用层,但是这样又有了耦合性,持久化框架变化的话要改变的代码会很多,甚至可以说是牵一发而动全身.

 

这位朋友跟我的想法完全合到一块了,最初我就是用service直接调用BaseDao的方法,Hql都写到service中。

但是当我认真审视整个项目结构的时候,我发现问题很大:如果将Hibernate换成MyBatis,不止是整个Dao层要修改,Service层也要做大量改动,而且改动之后单元测试也要重新做。

目前我的考虑可能跟LZ一样:老老实实针对一个model写一个Dao,对service只提供接口,具体实现可以根据使用什么框架定制开发,这样做的好处是:

我可以写多套Dao接口的实现类:Hibernate的、Mybatis的、甚至JDBC的,对项目的转型和升级影响小很多。

如果项目做成产品,持久层该用什么框架完全要看实际情况,那时就可以轻松实现框架的切换。

 

以上是我的拙见,不知可行否。

0 请登录后投票
   发表时间:2011-08-03  
楼主是否精通flex呢? 小弟想学,就是找不到师傅,各种问题各种有! 呵呵
0 请登录后投票
   发表时间:2011-08-03  
白糖_ 写道
feiyang404 写道

我个人认为,dao层只应提供数据持久化接口,和数据库,Service层均没有关系,如果持久化框架变了,比如不用Hibernate,而改用ibatIS,那么只需要将DAO里面的实现稍作改动,整个系统就可以流畅运行.所以,这就要求在Service层不要写HQL或者QBC,Service层专注调用DAO层接口为Action层提供服务,和DAO层无耦合.这样如果写一个通用DAO层的话,就会提高代码重用性,并且xml配置也很简洁,只要配置一个通用的dao就可以了,但是却使以牺牲灵活性为前提的,比如在Service层需要一个按属性查询的方法,那么在DAO层就要写where子句(where xxx=yyy),但是通用dao不可能知道xxx,怎么办呢?

 

如果通用DAO层接受Service层传来的HQL的话,那就会很容易写出一个灵活性高,重用性强的DAO通用层,但是这样又有了耦合性,持久化框架变化的话要改变的代码会很多,甚至可以说是牵一发而动全身.

 

这位朋友跟我的想法完全合到一块了,最初我就是用service直接调用BaseDao的方法,Hql都写到service中。

但是当我认真审视整个项目结构的时候,我发现问题很大:如果将Hibernate换成MyBatis,不止是整个Dao层要修改,Service层也要做大量改动,而且改动之后单元测试也要重新做。

目前我的考虑可能跟LZ一样:老老实实针对一个model写一个Dao,对service只提供接口,具体实现可以根据使用什么框架定制开发,这样做的好处是:

我可以写多套Dao接口的实现类:Hibernate的、Mybatis的、甚至JDBC的,对项目的转型和升级影响小很多。

如果项目做成产品,持久层该用什么框架完全要看实际情况,那时就可以轻松实现框架的切换。

 

以上是我的拙见,不知可行否。


是的  我觉得也很有道理

0 请登录后投票
   发表时间:2011-08-03  
楼主现在还在未这个问题担忧?dao和service都可以通过注解来搞定,不需要写那么多的配置文件!spring3.0是个好东西,它使代码变得简洁很多!
0 请登录后投票
   发表时间:2011-08-03  
通用Dao的查询处理上,我的意见是把语句独立出来,以Key value的方式保存到配置文件中。查询的时候输入Key和参数,Dao自动从配置中取语句进行查询。
这样一来,基本上只需要查单个的对象、查集合对象、计算结果这么几个方法就可以了。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics