动态查询的困惑

本文探讨了在使用JDBC进行数据库动态查询时遇到的问题,并分享了几种解决方案,包括使用Hibernate的DetachedCriteria进行离线查询,旨在提高查询效率及代码质量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

     最近又遇到了关于“动态查询”的需求, 之前在使用JDBC查询数据库时我就被这个问题所困扰过, 最终我是采取拼接字符串的方式。  后来知道了那样子很容易遭受SQL注入, 于是我就改成传参数的形式, 但是思想还是拼接SQL语句。 如下我的源代码:

     /**
  * 捐款情况查询
  */
 public List queryDonateInfo( final ContributeList contribute) {
  
  
  final DateConventer conventer = new DateConventer();
  
  List list = (List)this.getHibernateTemplate().execute(new HibernateCallback(){

   public Object doInHibernate(Session session)
     throws HibernateException, SQLException {
    List lstInfo;
    Date date;
    StringBuffer buffer =new StringBuffer("select f, d.name from Donated d inner join d.donateinfos f " +
      "where d.id="+contribute.getDonatedid());
    
    if(!"".equals(contribute.getDonatername().trim())){
     buffer.append(" and f.donatename=:donateName ");
    }
    
    if(!"".equals(contribute.getStartTime().trim())){
     date = conventer.transformDate(contribute.getStartTime().trim());
     buffer.append(" and f.donatetime>=:startTime ");
    }
    
    if(!"".equals(contribute.getEndTime().trim())){
     date = conventer.transformDate(contribute.getEndTime().trim());
     buffer.append(" and f.donatetime<=:endTime ");
    }
    
    Query query = session.createQuery(buffer.toString());
    
    if(!"".equals(contribute.getDonatername().trim())){
     query.setParameter("donateName", contribute.getDonatername());
    }
    
    if(!"".equals(contribute.getStartTime().trim())){
     date = conventer.transformDate(contribute.getStartTime().trim());
    query.setParameter("startTime", date);
    }
    
    if(!"".equals(contribute.getEndTime().trim())){
     date = conventer.transformDate(contribute.getEndTime().trim());
     query.setParameter("endTime", date);
    }
    lstInfo = query.list();
    Object[] obj = (Object[])lstInfo.get(0);
    String str =(String) obj[1];
    Donateinfo info =(Donateinfo) obj[0];
    System.out.println("捐款金额: "+info.getMoney());
    System.out.println("受捐者名字: "+str);
    return (List)lstInfo;
   }
   
  }
  
  );
  
  
  return list;
 }
      虽然问题是解决了, 但是觉得这种硬编码很麻烦而且不利于推广。

    ————改进1:  传入一个参数数组

         Query query = session.createQuery(hql);
      for (int i = 0; i < para.length; i++) {
       if (!para[i].equals(""))
        query.setString(i, para[i]);
      }

    但是此种改进其实并不可行, 因为sql语句是动态变化的。

   ——————改进2:  使用QBC  

   Java codeCriteria criteria = session.createCriteria(Person.class).setFirstResult(from).setMaxResults(number);
                if(null !=condition){
                    if(condition.getPersonCodeQuery() !=null &&!condition.getPersonCodeQuery().trim().equals("")){
                        criteria.add(Restrictions.like("personCode", condition.getPersonCodeQuery()+"%"));
                    }if(condition.getPersonIdBeginQuery() !=null &&!condition.getPersonIdBeginQuery().trim().equals("")){
                        criteria.add(Restrictions.ge("personID", new Integer(condition.getPersonIdBeginQuery())));
                    }if(condition.getPersonIdEndQuery() !=null &&!condition.getPersonIdEndQuery().trim().equals("")){
                        criteria.add(Restrictions.le("personID", new Integer(condition.getPersonIdEndQuery())));
                    }if(condition.getPersonSexQuery() != null &&!condition.getPersonSexQuery().trim().equals("")){
                        criteria.add(Restrictions.eq("personSex", condition.getPersonSexQuery()));
                    }
                }
                criteria1.list();

      —————— 还是不好 (Criteria by Example的方式)。

          最好要有某种框架就好了?

     ————改进3:  使用ibatis框架。  ibatis框架没有用过, 打算有时间再学习一下.....  .... 

 

    —————改进4:  构筑自己的动态查询框架。 ^_^  ^_^  

        关于动态SQL创建问题。一些复杂的查询比较灵活,功能强大。但是一般做法都hardcode,即在代码中根据前台用户输入的条件在程序代码中构建sql语句。感觉非常繁琐,而且代码质量不高。
   考虑:是否可以使用XML文件的形式来完成这项工作。
    1)不管查询组合情况如何,查询组合项是确定的。
    2)查询情况不外乎一下情况:
       比较运算符  =(等于)&gt;(大于) &lt;(小于) &gt;=(大于或等于) &lt;=(小于或等于) &lt;&gt;(不等于)
      
       逻辑运算符 ALL AND ANY BETWEEN EXISTS IN LIKE NOT OR SOME 
      
       在项目中设置这样一个资源文件
      
       &lt;组合项 动作名称=“actionName”&gt;
         &lt;属性名称=“actionFormProperty” 列名=“colName” 运算符=“”&gt;
       &lt;/组合项&gt;
      
       就像struts配置文件一样映射成config对象一样,将这些配置文件映射成对象。当请求某个action时,取得对应的actionForm的名称。然后根据这个actionForm来取得对应的查询组合对象。
       这样只要在上面映射对象的toSQL()方法就可以了。

      ——————————该觉实现这个太困难了, 不过还是有可能的吧。  加油!

 

——————————————-网上新发现: Hibernate3的DetachedCriteria支持————————————————————

    动态查询就是查询条件不确定的查询,或者说查询条件是根据用户传入的某些参数来生成的,在查询之前就已经生成了查询条件,hibernate中的查询条件一般都需要在取得session后才构造,而hibernate动态查询在取得session之前就已经构造好了查询条件,只是将查询条件作为参数传入到查询方法中,因此也叫离线查询,动态查询的条件可以在web层中就已经构造好了,例如servlet中,构造查询条件的方式如下:
DetachedCriteria dc=DetachedCriteria.forClass(User.class);
String name=request.getParameter("name");//接收参数
dc.add(Restrictions.eq("name",name));//此为约束条件,等于是用eq,还可以根据需要设置成大于小于等等
List users=dc(dc);//调用实现方法

实现查询方法如下:
public List dc(DetachedCriteria dc){
        Session s=HibernateUtil.getSession();//取得session
        Criteria c=dc.getExecutableCriteria(s);
        List list=c.list();
        s.close();
        return list;
    }
上面的方法就可以完成动态条件查询
 

     个人点评:   ^_^  ^_^   这种做法的好处在于:

     查询语句的构造完全被搬离到web层实现,而业务层则只负责完成持久化和查询的封装即可,与查询条件构造完全解耦。

     但是在WEB曾的条件构造还是回到了我上述论述的老问题。  ^_^  ^_^ 

 ——————————————————————————————————————————————————————

    哪位朋友要是有好的方法, 要不吝赐教呀!  ^_^  ^_^  

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值