`

JDBC的多条件动态查询

    博客分类:
  • Java
阅读更多

 

前面我已经提到了现在的项目无非就是列表里的分页加多条件查询,在http://xdwangiflytek.iteye.com/blog/1358080里我已经简单的归纳了一下分页的实现手段和JDBC里的分页,这里我们在来说说JDBC里的多条件动态查询,为什么说多条件,因为在项目列表中,不可能只有只有一个字段,所以说条件也不可能只有一个,所以这里我们还是说一下多条件下的查询,多条件ok了那么单个条件不更ok了么(Hibernate里有Criteria Queries哦)。

首先我们和分页一样先分析一下多条件综合查询的实现方式有哪些?

1、直接将参数值拼接到SQL语句中,然后进行Select,但是说这种方式存在安全性问题,比如说SQL的注入,尽管我们可以通过正则等手段来过滤掉这些特殊字符,但是这样看上去不是很爽。

2、先使用占位符“?”来拼接SQL,然后再通过条件判断去填充PreparedStatement,但是这种方式显然很麻烦,因为我们在拼SQL的时候需要判断一次,在填充pst的时候还需要再进行判断,所以不是好的解决方案。

3、存储过程,这个因为本人对存储过程认识不是很深,所以这里不加描述;

其实方法很多,只是找一个相对好一点的,工作的这段时间做.NET项目时使用里面的SqlHelper感觉很犀利,记得以前学习的时候老师也给我们做了一个类似的,所以想写一个工具类。

 

Parameter.java:

package com.iflytek.page;

/**
 * 查询参数工具类,用于表示条件参数对象
 * 
 * @author xudongwang 2012-1-19
 * 
 *         Email:xdwangiflytek@gmail.com
 */
public class Parameter {
	/**
	 * 数据库字段名
	 */
	private String field;
	/**
	 * 参数值 Object
	 */
	private Object value;
	/**
	 * 数据库操作符 =、>=、<、like...
	 */
	private String operator;

	/**
	 * 构造方法
	 * 
	 * @param field
	 *            数据库字段名
	 * @param operator
	 *            数据库操作符 =、>=、<、like...
	 * @param value
	 *            参数值 Object
	 */
	public Parameter(String field, String operator, Object value) {
		super();
		this.field = field;
		this.value = value;
		this.operator = operator;
	}

	public String getField() {
		return field;
	}

	public Object getValue() {
		return value;
	}

	public String getOperator() {
		return operator;
	}
}

 

 DynamicQuery.java:

package com.iflytek.page;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;

/**
 * 动态查询工具类,用于拼接SQL、填充PreparedStatement
 * 
 * @author xudongwang 2012-1-19
 * 
 *         Email:xdwangiflytek@gmail.com
 */
public class DynamicQuery {

	private String templet = " AND %s %s ?";
	private String baseSql;
	private ArrayList<Parameter> parameters = new ArrayList<Parameter>();

	public DynamicQuery() {

	}

	/**
	 * baseSql需要带有where条件
	 * 
	 * @param baseSql
	 */
	public void setBaseSql(String baseSql) {
		this.baseSql = baseSql;
	}

	public void addParameter(Parameter parameter) {
		parameters.add(parameter);
	}

	public String generateSql() {
		StringBuffer sb = new StringBuffer(baseSql);
		for (Parameter parameter : parameters) {
			sb.append(String.format(templet, parameter.getField(),
					parameter.getOperator()));
		}
		return sb.toString();
	}

	public void fillPreparedStatement(PreparedStatement pst)
			throws SQLException {
		int count = 1;
		for (Parameter p : parameters) {
			// 这里使用SetObjcet的缺点是失去了类型的验证功能,如果大家不嫌麻烦,可以判断,根据类型,set不同的类型
			pst.setObject(count, p.getValue());
			count++;
		}
	}

}

 

 SelectServlet.java:

	DynamicQuery query = new DynamicQuery();
		query.addParameter(new Parameter("name", "like", "xudongwang"));
		query.addParameter(new Parameter("email", "=", "xdwangiflytek@gmail.com"));
		StudentDao studentDao = new StudentDao();
		List<Stduent> students = studentDao.selectByQuery(query);
		request.setAttribute("students", students);

 

StduentDao.java:

public List<Student> selectByQuery(DynamicQuery query) {  
        
        List<Student> students = new ArrayList<Student>();  
  
        try {  
            String sql = "SELECT id,name,email FROM tbl_stduent";  
  
            query.setBaseSql(sql);  
            //如果想排序,自行在sql后添加  
            sql = query.generateSql();
            Connection conn = null;  
            try {  
                conn = DbUtil.getConnection();  
                PreparedStatement pst= conn.prepareStatement(sql);  
              //填充pst  
                query.fillPreparedStatement(pst);
                ResultSet rs = pst.executeQuery();  
                while (rs.next()) {  
                    Student student = new Student();  
                    ……  
                    students.add(student);  
                }  
                rs.close();  
                pst.close();  
            } finally {  
                if (conn != null) {  
                    conn.close();  
                }  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return students;  
    }
 

 

下面来总结一下上面的整个流程:

 1、 首先我们在ServletAction等控制器里将需要查询的表单参数值添加到查询条件列表中;

 2、 在数据访问层DAO中设置基本的SQL

 3、 下面我们来迭代查询条件列表,使用占位符拼接SQL

 4、 DAO中拿SQL创建PreparedStatement

 5、 迭代查询条件列表,为pst填充值;

 6、 接下来,没有特殊(是否添加排序)的地方了,就是正常的executeQuerywhile(rs.next()){...}

Ok88.

 

 

1
1
分享到:
评论
2 楼 drinkjava2 2016-11-23  
太复杂了而且不通用,利用ThreadLocal可完美解决这一问题,参见 http://drinkjava2.iteye.com/blog/2340020
以下为代码示例,参数利用q()方法暂存到Threadlocal中去,在SQL执行中取出来并装入preparedStatement:
public int conditionQuery(int condition, Object parameter) {//动态拼接SQL查询   
            User u = new User();   
            String sql = "Select count(*) from " + u.Table() + " where ";   
            if (condition == 1 || condition == 3)   
                sql = sql + u.UserName() + "=" + q(parameter) + " and " + u.Address() + "=" + q("Address1");   
       
            if (condition == 2)   
                sql = sql + u.UserName() + "=" + q(parameter);   
       
            if (condition == 3)   
                sql = sql + " or " + u.Age() + "=" + q(parameter);   
       
            return Dao.dao.queryForInteger(sql);   
        }   
       
        @Test   
        public void doJdbcConditionQuery() {   
            Assert.assertEquals(1, conditionQuery(1, "User1"));   
            Assert.assertEquals(0, conditionQuery(2, "User does not exist"));   
            Assert.assertEquals(1, conditionQuery(3, 10));   
            Assert.assertEquals(0, conditionQuery(3, 20));   
        }   
1 楼 jianxia801 2012-07-10  
哥们你的文章不错,值得一读!

相关推荐

    Java中JDBC实现动态查询的实例详解

    从多个查询条件中随机选择若干个组合成一个DQL语句进行查询,这一过程叫做动态查询。下面通过实例代码给大家讲解JDBC实现动态查询的方法,需要的朋友参考下吧

    java配合MyBatis 多条件查询及动态SQL

    MyBatis 多条件查询及动态SQL 粉丝可见 ybb_ymm 已于 2023-02-02 11:09:17 修改 642 收藏 3 分类专栏: java 文章标签: mybatis sql mysql 编辑 版权 java 专栏收录该内容 104 篇文章2 订阅 背景 MyBatis是一...

    自定义查询框架Criteria

    最近一个项目 需要 条件动态配置,客户简单了 但是涉及到开发就麻烦了 首先数据量很大 几百个G 单表就有千万数据 其次 关联表很多 科研查询可以包括一百多条查询条件可自动配置。 但是mybatis肯定处理不了那么复杂...

    基于spring-jdbc生态的(No-ORM)DBUtil,常用于动态结构的场景

    基于spring-jdbc生态的(No-ORM)DBUtil,常用于动态结构的场景,如:可视化动态多数据源、低代码后台、物联网车联网数据处理、数据清洗、异构数据库迁移同步、运行时自定义表单/查询条件/数据结构、爬虫数据解析、自定义...

    jdbc基础和参考

    1.写一条恒成立的select语句,无论你输入的条件是什么,总是能讲表中的所有数据输出 select id,last_name from s_emp where '1' ='1'; where 1=1; findByOption(Integer age,String province,String gender){ ...

    用传参数的方法实现Java对SQLite的添加和查询

    用传参数的方法实现Java对SQLite的添加和查询(不用拼接sql语句的方法,不用屏蔽单引号,工程包括sqlite-jdbc-3.27.2.1.jar)

    dbVisitor 是一个数据库 ORM 工具

    提供对象映射、丰富的类型处理、动态SQL、存储过程、内置分页方言20+、 支持嵌套事务、多数据源、条件构造器、INSERT 策略、多语句/多结果。兼容 Spring 及 MyBatis 用法。 它不依赖任何其它框架,因此可以很方便的...

    Sqlbean是一款通过Java语法生成SQL语句的ORM插件

    内置大量常用方法,支持灵活的条件查询,无DAO层,在项目中几乎不需要编写SQL语句,帮助你快速进行业务功能开发,除了支持Mybatis也同时支持Spring Jdbc。 多数据源, 动态Schema, 读写分离, 自动建表, 自动维护表...

    Mybatis的综合案例-学生信息查询系统

    详细解释了什么是动态SQL,可以根据不同条件动态构建SQL语句,避免大量重复代码。 介绍了动态SQL常用元素:、、、、、等。 使用动态SQL可以实现高度灵活的数据库交互,适用于复杂业务场景。 可以作为学习动态SQL的参考,...

    支持多数据库的ORM框架ef-orm.zip

    IQueryableEntity允许你将一个实体直接变化为一个查询(Query),在很多时候可以用来完成复杂条件下的数据查询。比如 ‘in (?,?,?)’, ‘Between 1 and 10’之类的条件。 xxQL有着拼装语句可读性差、编译器无法...

    spring-data-ebean:用于Spring数据的Ebean实现,简化了创建基于Ebean的数据访问层的开发。超简单,超强大的ORM框架,OQL,SQL,ES多查询引擎,超越JPA,Hibernate,Mybatis

    根据查询方法名称和注释动态生成查询 支持查询渠道服务 通过查询方法透明触发Ebean查询 提供基本属性的实现域基类 支持透明审核(创建,最后更改) 集成自定义存储库代码的可能性 Easy Spring与自定义名称空间的...

    mybatis的具体介绍.doc

    灵活性高:MyBatis支持动态SQL和存储过程,提供了强大的动态SQL支持,使得查询条件可以根据需要进行灵活拼装,便于处理多变的查询需求。 性能高效:MyBatis是一个轻量级的框架,其性能高效,直接映射SQL语句和Java...

    项目管理-Mybatis学习源码(三)

    MyBatis 是一个开源的持久层框架,它为 Java 程序...动态 SQL:MyBatis 提供了强大的动态 SQL 功能,可以根据条件动态生成不同的 SQL 语句,减少了代码冗余和提高了灵活性。 缓存支持:MyBatis 提供了一级缓存和二级

    项目管理-mybatis学习源码(二)

    MyBatis 是一个开源的持久层框架,它为 Java 程序...动态 SQL:MyBatis 提供了强大的动态 SQL 功能,可以根据条件动态生成不同的 SQL 语句,减少了代码冗余和提高了灵活性。 缓存支持:MyBatis 提供了一级缓存和二级

    项目管理-Mybatis学习源码(一)

    MyBatis 是一个开源的持久层框架,它为 Java 程序...动态 SQL:MyBatis 提供了强大的动态 SQL 功能,可以根据条件动态生成不同的 SQL 语句,减少了代码冗余和提高了灵活性。 缓存支持:MyBatis 提供了一级缓存和二级

    struts2+spring3+hibernate4 + UI 组件(easyui)+代码生成器+共通封装+Spring_security权限

    页面加查询条件,后台不需要写任何逻辑判断,动态拼SQL追加查询条件 [3].常用共通封装 数据字典封装, 邮件发送封装,定时器封装,hibernate+spring jdbc组合使用 [4].完整用户权限封装 权限可直接使用 功能:权限,...

    Java开发实战1200例(第1卷).(清华出版.李钟尉.陈丹丹).part3

    2.3 条件语句 38 实例028 判断某一年是否为闰年 38 实例029 验证登录信息的合法性 39 实例030 为新员工分配部门 40 实例031 用Switch语句根据消费金额计算折扣 41 实例032 判断用户输入月份的季节 42 2.4 循环控制 ...

Global site tag (gtag.js) - Google Analytics