问题描述
我用SSH开发Web应用。现在有一个问题一直困扰着我。对于数据的增、删、改很好设计了。前台页面表单传入参数以后,action类将值填充到实体对象里,然后将实体传给Service的增、删、改方法,Service调用Dao相应的方法,将实体传给Dao,Dao将数据保存到数据存中。现在就是查询数据的设计很有问题。如果我在Service里设计各种查询方法如:findUserByName(StringuserName);findUserById(Integerid);或findUser(param1,param2,.....paramN)然后Service根据不同的查询方法来生成查询语句,再调用dao来查询数据。因为系统里有各式各样的查询,所以Service里的查询方法会很多。而且有时候同一个查询,仅仅是因为查询的参数不同(如:findUserByName和findUserById)就得写二个方法。这样设计总觉得太恶~~可是又没有想到更好的设计思路。大家在设计系统时,对查询方面是如何做的?希望大家都说说,看看哪种设计更好一些。请考虑多表关联、排序、分组等情况。
解决方案
解决方案二:
我很纠结的发现怎么会考虑到这么多??普通的增删改查还行这些关联啊什么的都来了可能吗?如果可能的话倒是要请教了。
解决方案三:
表和表之间的关联关系是很普通的啊。怎么会不可能呢?
解决方案四:
独立表来做比较多移动上百万都是独立的---------------------------------------------------------------------------------------------http://www.jiemengwu.com/http://www.phpzy.com/php/http://www.shopfw.com
解决方案五:
你们的意思是,做成独立的表是现在主流的设计方向?
解决方案六:
这个service方法的多少和表的设计有什么关系啊
解决方案七:
和表的设计没什么关系。和系统里有多少种查询情况有关。我的困惑就在于此。我想知道大家都是怎么设计查询这部分的。
解决方案八:
直接传where后面的条件方法只有find
解决方案九:
举个例子:User有三个属性User.id,User.name,User.lastLoginTime有些时候我们只想使用id查到一个user那在service里定义一个方法findUserById(Integerid);有些时候我们又想通过name来找到一个user于是又有了findUserByName(Stringname);而通过name来查找的时候,有时候希望是精确查找,有时候又希望是模糊(like)查找,又该怎么办?再定义一个方法?findUserByLikeName(Stringname);有些时候我们想找用户最后登录时间大于某个时间的用户:findUserByLastLoginTime(lastLoginTime);有些时候我们又想找最后登录时间再一个时间范围的用户,是不是又要加一个查询啊?findUserByLastLoginTime(beginTime,endTime);楼上说只有一个find方法,直接传where后面的条件。我想问的是像上面的情况该怎么传?
解决方案十:
通过id查询rules=rulesSer.find("andruleId='"+ruleId+"'");通过name和id查询Stringsql="";if(rul_name!=null&&!rul_name.equals("")){sql+="andnamelike'%"+rul_name+"%'";}if(id!=null&&!id.equals("")){sql+="andclsId='"+id+"'";}countRows=0;List<RulesObj>rules=rulesSer.findRul(sql);不知道这样能不能满足你的要求
解决方案十一:
其实分开写虽然代码量多一些,但是很清晰啊,混在一起容易有问题,后期维护也不好弄
解决方案十二:
楼主貌似是jdbc不是ssh
解决方案十三:
其实。。可以这样来。在通用的Dao里写一个find方法。publicabstractclassAbstractDao{/**通用的查询方法*参数说明:targetClass:目标类;props:查询中被限定的属性;condition:被限定属性的值;limit:查询的记录数*/publicObject[]find(ClasstargetClass,Object[]props,Object[]condition,intlimit){//做查询工作,拼接HQL或者SQL语句神马的returnfindResultSet;//返回查询结果(集)}}
解决方案十四:
引用12楼psjcarlos的回复:
其实。。可以这样来。在通用的Dao里写一个find方法。JavacodepublicabstractclassAbstractDao{/**通用的查询方法*参数说明:targetClass:目标类;props:查询中被限定的属性;condition:被限定属性的值;limit:查询的记录数*/publi……
或者你可以把props和condition合起来当做一个Map传入,这样更加清晰
解决方案十五:
publicstaticvoidfind(intid,Stringname,Stringtime){StringBuffersb=newStringBuffer();sb.append("select*fromuserwhere");if(!("").equals(id)){sb.append("id="+id);}if(name!=null){sb.append("name="+name);}if(time!=null){sb.append("time="+time);}//查询方法....}
这种方法可行不?
解决方案:
参数不定的情况下我一般对参数封装,譬如查询只有一个find方法,里面参数只有一个Map对象。缺点是自己必须要记住每项参数的key值
解决方案:
该回复于2011-01-30 15:14:06被版主删除
解决方案:
to:qingshan002008从哪看出我是jdbc?呵。to:psjcarlospublicabstractclassAbstractDao{/**通用的查询方法*参数说明:targetClass:目标类;props:查询中被限定的属性;condition:被限定属性的值;limit:查询的记录数*/publicObject[]find(ClasstargetClass,Object[]props,Object[]condition,intlimit){//做查询工作,拼接HQL或者SQL语句神马的returnfindResultSet;//返回查询结果(集)}}我也一直在想你这种方法,不过不容易实现。按你现在定义的。那个targetClass就不行,只能查询一个目标。。多表关联怎么查?
解决方案:
引用17楼truezerg的回复:
to:qingshan002008从哪看出我是jdbc?呵。to:psjcarlospublicabstractclassAbstractDao{/**通用的查询方法*参数说明:targetClass:目标类;props:查询中被限定的属性;condition:被限定属性的值;limit:查询的记录数*/……
按照通常的设计,每一个实体类(Entity)对应着一个数据访问类(Dao),这个dao负责封装相应entity的简单的CRUD。加入有两个实体类ClassA,ClassB。有以下关系:publicclassClassA{intid;ClassBb;}以HQL为例,需要查找id为1的ClassA对象(并且同时查找出这个对象中的b属性),这句语句可以实现:FROMClassAASaWHEREa.id=1这样的查询,完全可以通过上面那个方法来实现,targetClass指定为ClassA.class即可(我不知道这样是不是你说的“多个表关联”)。
解决方案:
该回复于2011-02-09 09:25:10被版主删除
解决方案:
该回复于2011-02-09 09:25:10被版主删除
解决方案:
该回复于2011-02-09 09:25:10被版主删除
解决方案:
如果表很多,而且关系很复杂,数据量又大,查询条件比较复杂的话(比方说需要JOINGROUPHAVING或者聚合之类的)DAO封装得不偿失。不如之间SQL便捷搞效。用HibernateSQLQuery,结合addEntity(),这样比纯JDBC查询,然后自己装配对象字段要简单些,是个折衷。
解决方案:
findUserByName(StringuserName);findUserById(Integerid);如果只是这样的操作,你直接findUserBy就可以了,反正你查来查去还是查这个User对象,而属性都在User对象里面,把User对象传到Dao,然后在进行判断User对象里面的属性是否NotNull,具体是要查什么,看具体的情况具体对待吧~
解决方案:
该回复于2011-02-09 13:30:08被版主删除
解决方案:
publicObject[]find(ClasstargetClass,Object[]props,Object[]condition,intlimit){我感觉这种方法更乱,把属性、查询条件都暴露给了业务层。业务层不是在做业务,而是在拼查询条件了。既然用了DAO,那就不应该把查询条件相关的东西暴露给业务层。
解决方案:
引用25楼bao110908的回复:
publicObject[]find(ClasstargetClass,Object[]props,Object[]condition,intlimit){我感觉这种方法更乱,把属性、查询条件都暴露给了业务层。业务层不是在做业务,而是在拼查询条件了。既然用了DAO,那就不应该把查询条件相关的东西暴露给业务层。
这种东西应该在DAO内使用,并将方法修饰改为private。对外,还是暴露findUserById之类的方法。
解决方案:
我也在写的过程中有过类似的疑问我最后的做法是分开findUserByIdfindUserByName
解决方案:
引用26楼bao110908的回复:
引用25楼bao110908的回复:publicObject[]find(ClasstargetClass,Object[]props,Object[]condition,intlimit){我感觉这种方法更乱,把属性、查询条件都暴露给了业务层。业务层不是在做业务,而是在拼查询条件了。既然用了DAO,那就不应该把查询条件相关的东西暴露给业务层。……
这个是一个经验问题。将相同的SQL部分放入一个private方法整合起来。如果两句SQL只是一个条件不同的话。同时对外暴露public方法,内部调用这个核心的private方法。如果本来是findUserByIdfindUserByName这样的结构。那么最后你写的时候应该是findUserByIdfindUserByNamefindUser(private)这样的。这样,如果业务发生改动,你只需要修改findUser就ok。而实际调用的逻辑则分散在另外两个方法里
解决方案:
我觉得还是用HQL语句多表联查还是很好的选择。。
解决方案:
楼主写个通用的DAO吧,我之前也是也一个业务写一个DAO,这两天全部都删掉,写个通用的DAO,一个就够了,其它地方都可以调用。
解决方案:
楼主有邮箱吗?我给你发个源代码!
解决方案:
使用findUserByxxxx(Stringxxx);findUserByxxxx(Integerxxx);之类的吧,用那种find的方法维护难不说,效率也是个问题。
解决方案:
该回复于2011-02-09 10:31:00被版主删除
解决方案:
该回复于2011-02-09 10:19:49被版主删除
解决方案:
有时对多条件查询你可以一次传多个参数么在DAO里判断下空就可以了sql="select*fromtablewhere1=1";if(a!=null&&!"".equals(a)){sql+="ANDa='"+a+"'";}
把条件加到语句后面就行了么!
解决方案:
引用35楼shanxmxj的回复:
Javacode有时对多条件查询你可以一次传多个参数么在DAO里判断下空就可以了sql="select*fromtablewhere1=1";if(a!=null&&!"".equals(a)){sql+="ANDa='"+a+"'";}把条件加到语句后面就行了么!
呵呵,这个问题很大,一个SQL注入,就挂了!
解决方案:
引用22楼beowulf2005的回复:
如果表很多,而且关系很复杂,数据量又大,查询条件比较复杂的话(比方说需要JOINGROUPHAVING或者聚合之类的)DAO封装得不偿失。不如之间SQL便捷搞效。用HibernateSQLQuery,结合addEntity(),这样比纯JDBC查询,然后自己装配对象字段要简单些,是个折衷。
这个观点不错,hibernate毕竟有利有弊
解决方案:
封装下
解决方案:
我觉得不要太省事了,service层多写几个方法没有什么的,这样业务更加清晰,维护更加方便,如果都做成通用的那种,多表关联之间的查询就是个问题,为什么都要做成通用的了?单独的查询岂不是更好
解决方案:
弄个BaseDao,其他的dao从他继承,BaseDao提供公用的方法
解决方案:
//UserService.javapublicList<User>findUserByName(Stringname){userDao.findUserListByProperty("name",name);}publicList<User>findUserByAge(intage){userDao.findUserListByProperty("age",newInteger(age));}publicUserfindUserById(Stringid){userDao.findUserByProperty("id",id);}//UserDAO.javapublicList<User>findUserListByProperty(StringpropertyName,Objectvalue){try{StringqueryString="fromUserowhereo."+propertyName+"=?";Queryquery=this.getHibSession().createQuery(queryString);query.setParameter(0,value);returnquery.list();}catch(RuntimeExceptionre){throwre;}}publicUserfindUserByProperty(StringpropertyName,Objectvalue){try{StringqueryString="fromUserowhereo."+propertyName+"=?";Queryquery=this.getHibSession().createQuery(queryString);query.setParameter(0,value);return(User)query.uniqueResult();}catch(RuntimeExceptionre){throwre;}}
解决方案:
另findUserListByProperty和findUserByProperty之类的方法亦可以写在baseDao中,通过类模板方式使用如下:publicTfindByProperty(StringpropertyName,Objectvalue){try{log.debug("finding"+class_.getSimpleName()+"instancewithproperty:"+propertyName+",value:"+value);StringqueryString=this.getDataHqlBase()+"owhereo."+propertyName+"=?";Queryquery=this.getSession().createQuery(queryString);query.setParameter(0,value);return(T)query.uniqueResult();}catch(RuntimeExceptionre){log.error("findbypropertyfailed",re);throwre;}}
解决方案:
这么多高手啊
解决方案:
其实现在很多都是把关联的多表改成单表来实现的,你用一个类来完成基本的操作,在继承也可以达到重用啊,而且对后期维护和效率都有好处啊
解决方案:
楼主不要什么都用hibernate来搞啊,数据库表之间要建关联,如果只是通过hibernate映射来建表之间的关联,对以后表的维护部太直观.而且如果是大型项目,业务比较复杂,表比较复杂,关联比较多,不建关联出问题了怎么查找想要的数据??至于查询怎么设计,如果遇到复杂的查询都是写Hql语句,,当然有些hql不支持的就用sql语句.设计的时候分为单表查询,和复杂表查询.单表代码如下就行了publicList<User>findUserByName(Stringname){userDao.findUserListByProperty("name",name);}publicList<User>findUserByAge(intage){userDao.findUserListByProperty("age",newInteger(age));}publicUserfindUserById(Stringid){userDao.findUserByProperty("id",id);}
多表的复杂业务就要单独的写hql或者sql.如果多表查询还要写成上面那样.如果业务复杂,要查询40个表结构,是不是要进行40次数据库连接,调用40次service或者dao???
解决方案:
不是很理解,但是我觉得可以用这样的findUser(Useruser);这样的话,无论几个参数都可以搞定。