锁定老帖子 主题:关于DAO层的疑惑!!!平地一声雷
精华帖 (0) :: 良好帖 (1) :: 新手帖 (14) :: 隐藏帖 (6)
|
|
---|---|
作者 | 正文 |
发表时间:2011-08-03
DAO的终极目标是DAL,也就是说只有真正需要经历数据量历练的项目,DAO才是必须
|
|
返回顶楼 | |
发表时间:2011-08-03
每个实体类提供一个DAO 继承 BaseDAO,一些基本的操作 都放在 BaseDAO 里面
|
|
返回顶楼 | |
发表时间: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者到底应该放置什么样的代码,他们的职能划分才是关键 |
|
返回顶楼 | |
发表时间: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框架恐怕无法无缝直接支持事务。 |
|
返回顶楼 | |
发表时间: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工具类,泛型+反射。 |
|
返回顶楼 | |
发表时间: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的,对项目的转型和升级影响小很多。 如果项目做成产品,持久层该用什么框架完全要看实际情况,那时就可以轻松实现框架的切换。
以上是我的拙见,不知可行否。 |
|
返回顶楼 | |
发表时间:2011-08-03
楼主是否精通flex呢? 小弟想学,就是找不到师傅,各种问题各种有! 呵呵
|
|
返回顶楼 | |
发表时间: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的,对项目的转型和升级影响小很多。 如果项目做成产品,持久层该用什么框架完全要看实际情况,那时就可以轻松实现框架的切换。
以上是我的拙见,不知可行否。
|
|
返回顶楼 | |
发表时间:2011-08-03
楼主现在还在未这个问题担忧?dao和service都可以通过注解来搞定,不需要写那么多的配置文件!spring3.0是个好东西,它使代码变得简洁很多!
|
|
返回顶楼 | |
发表时间:2011-08-03
通用Dao的查询处理上,我的意见是把语句独立出来,以Key value的方式保存到配置文件中。查询的时候输入Key和参数,Dao自动从配置中取语句进行查询。
这样一来,基本上只需要查单个的对象、查集合对象、计算结果这么几个方法就可以了。 |
|
返回顶楼 | |