`

让DbUtils支持NamedParameter方式的sql

    博客分类:
  • java
阅读更多
DbUtils代码很精悍,很多中小型项目都用它来编写持久层,但是不够强大,平时用习惯了spring jdbc的NamedParameter方式的sql(形如:select * from user where name=:name),总觉得还缺点功能,干脆仿照spring jdbc写个类似的sql处理方法,造个小小小轮子,代码留念:
import java.util.ArrayList;
import java.util.List;

/**
 * 此类封装NamedParameterSql
 * 
 * @author zl
 *
 */
public class ParsedSql {
	
	private String originalSql;
	//参数名
	private List<String> paramNames = new ArrayList<String>();
	//参数在sql中对应的位置
	private List<int[]> paramIndexs = new ArrayList<int[]>();
	//统计参数个数(不包含重复)
	private int namedParamCount;
	//统计sql中?的个数
	private int unnamedParamCount;
	
	private int totalParamCount;
	
	public ParsedSql(String originalSql){
		this.originalSql = originalSql;
	}
	
	public List<String> getParamNames() {
		return paramNames;
	}

	public void addParamNames(String paramName,int startIndex,int endIndex) {
		paramNames.add(paramName);
		paramIndexs.add(new int[]{startIndex,endIndex});
	}

	public int[] getParamIndexs(int position) {
		return paramIndexs.get(position);
	}


	public String getOriginalSql() {
		return originalSql;
	}

	
	public int getNamedParamCount() {
		return namedParamCount;
	}

	public void setNamedParamCount(int namedParamCount) {
		this.namedParamCount = namedParamCount;
	}

	public int getUnnamedParamCount() {
		return unnamedParamCount;
	}

	public void setUnnamedParamCount(int unnamedParamCount) {
		this.unnamedParamCount = unnamedParamCount;
	}

	public int getTotalParamCount() {
		return totalParamCount;
	}

	public void setTotalParamCount(int totalParamCount) {
		this.totalParamCount = totalParamCount;
	}

	public String toString(){
		return this.originalSql;
	}

}


sql处理工具类
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 带参数sql处理工具类
 * 
 * @author zl
 *
 */
public class NamedParameterUtils {
	
	//定义特殊字符(参考spring jdbc N多)
	private static final char[] PARAMETER_SEPARATORS =
		new char[] {'"', '\'', ':', '&', ',', ';', '(', ')', '|', '=', '+', '-', '*', '%', '/', '\\', '<', '>', '^'};
	
	
	/**
	 * 对带参数sql的统计式封装,便于后续肢解拼装(恐怖啊。。。。。)
	 * @param originalSql
	 * @return
	 */
	public static ParsedSql parserSqlStatement(String originalSql) {
		ParsedSql parsedSql = new ParsedSql(originalSql);
		Set<String> paramNames = new HashSet<String>();
		char[] sqlchars = originalSql.toCharArray();
		int namedParamCount = 0;
		int unNamedParamCount = 0;
		int totalParamCount = 0;
		int i = 0;
		while(i<sqlchars.length){
			char statement = sqlchars[i];
			if(statement==':'||statement=='&'){
				int j = i+1;
				while(j<sqlchars.length&&!isSeparatorsChar(sqlchars[j])){
					j++;
				}
				if(j-i>1){
					String paramName = originalSql.substring(i+1, j);
					if(!paramNames.contains(paramName)){
						paramNames.add(paramName);
						namedParamCount++;
					}
					parsedSql.addParamNames(paramName, i, j);
					totalParamCount++;
				}
				i=j-1;
			}else if(statement=='?'){
				unNamedParamCount++;
				totalParamCount++;
			}
			i++;
		}
		parsedSql.setNamedParamCount(namedParamCount);
		parsedSql.setUnnamedParamCount(unNamedParamCount);
		parsedSql.setTotalParamCount(totalParamCount);
		return parsedSql;
	}
	
	/**
	 * 获得不带参数的sql,即替换参数为?
	 * @param parsedSql
	 * @param params
	 * @return
	 */
	public static String substituteNamedParams(ParsedSql parsedSql,Map<String,Object> params){
		String original =parsedSql.getOriginalSql();
		StringBuffer actual = new StringBuffer("");
		int lastIndex = 0;
		List<String> paramNames = parsedSql.getParamNames();
		for(int i=0;i<paramNames.size();i++){
			int[] indexs = parsedSql.getParamIndexs(i);
			int startIndex = indexs[0];
			int endIndex = indexs[1];
			String paramName = paramNames.get(i);
			actual.append(original.substring(lastIndex, startIndex));
			if(params!=null&&params.containsKey(paramName)){
//				if(){}
				actual.append("?");
			}else{
				actual.append("?");
			}
			lastIndex = endIndex;
		}
		actual.append(original.subSequence(lastIndex, original.length()));
		return actual.toString();
	}
	
	/**
	 * 获得sql所需参数
	 * @param parsedSql
	 * @param params
	 * @return
	 */
	public static Object[] buildValueArray(ParsedSql parsedSql,Map<String,Object> params){
		List<String> paramNames = parsedSql.getParamNames();
		Object[] obj = new Object[parsedSql.getTotalParamCount()];
		if(parsedSql.getNamedParamCount()>0&&parsedSql.getUnnamedParamCount()>0){
			throw new RuntimeException("parameter方式与?方式不能混合!");
		}
		for(int i=0;i<paramNames.size();i++){
			String keyName = paramNames.get(i);
			if(params.containsKey(keyName)){
				obj[i]=params.get(keyName);
			}
		}
		return obj;
	}
	
	protected static boolean isSeparatorsChar(char statement){
		if(Character.isWhitespace(statement)){
			return true;
		}
		for(int i=0;i<PARAMETER_SEPARATORS.length;i++){
			if(statement==PARAMETER_SEPARATORS[i]){
				return true;
			}
		}
		return false;
	}
}


最终测试使用:
import java.beans.PropertyDescriptor;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.MapListHandler;


public class JDBCTemplement {
	
	protected QueryRunner runner;
	
	protected Connection conn;
	
	public JDBCTemplement(DataSource datasource) throws SQLException {
		runner = new QueryRunner(datasource);
		conn = datasource.getConnection();
		conn.setAutoCommit(false);
	}
	

	
	public List<Map<String,Object>> queryAsList(String sql) throws SQLException{
		List<Map<String,Object>> result = new ArrayList<Map<String,Object>>();
		result = runner.query(sql, new MapListHandler(){
			public List<Map<String, Object>> handle(ResultSet rs) throws SQLException {
				return this.handle(rs);
			}
			
		});
		return result;
	}

	public List<Map<String,Object>> queryAsList(String sql,Map<String,Object> param) throws SQLException{
		if(null==param){
			return this.queryAsList(sql);
		}
		ParsedSql parsedSql = NamedParameterUtils.parserSqlStatement(sql);
		String actualSql = NamedParameterUtils.substituteNamedParams(parsedSql, param);
		Object[] obj = NamedParameterUtils.buildValueArray(parsedSql, param);
		
		List<Map<String,Object>> result = new ArrayList<Map<String,Object>>(); 
		result = runner.query(actualSql, new MapListHandler(){
			@Override
			public List<Map<String, Object>> handle(ResultSet rs)
					throws SQLException {
				return this.handle(rs);
			}}, obj);
		return result;
	}
	
}
分享到:
评论

相关推荐

    dbutils dbutils dbutils dbutils

    只需简单几行代码,就可以将现有的数据库模块升级到支持连接池的版本。 3. **Transaction**: 提供事务处理功能,可以自动或手动开启和提交事务。在数据库操作中,事务处理是确保数据一致性的重要手段,DBUtils 的 ...

    JAVA操作SQL Sever数据库的驱动与DBUtils API

    本话题主要聚焦于如何使用JAVA操作SQL Server数据库,特别是通过SQLJDBC驱动和Apache的DBUtils API。 首先,SQLJDBC驱动是微软提供的用于Java应用程序连接到SQL Server的驱动程序。它实现了JDBC接口,使得Java...

    DBUtils操作数据库以及事物的管理

    相比于传统的JDBC编程方式,DBUtils提供了更加简洁、高效的API,并且在一定程度上提高了代码的可读性和可维护性。 #### 二、环境搭建 在使用DBUtils之前,首先需要搭建好开发环境。这里涉及到的主要依赖包括...

    Dbutils 的jar包

    QueryRunner支持预编译的PreparedStatement,能有效防止SQL注入攻击。 2. **ResultSetHandler**:这个接口用于处理查询结果集。Dbutils 提供了几种常见的实现,如 `ArrayListHandler`(将结果集转换为 List), `...

    模仿DBUtils(自己模仿DBUtils写的简易DBUtils)

    6. **批处理**: DBUtils支持批处理操作,允许一次发送多条SQL语句,提高数据库操作的效率。在你的实现中,可能会找到如何使用批处理的方法。 7. **配置与初始化**: DBUtils通常需要配置数据库连接参数,如URL、...

    commons-dbutils-1.4.jar

    2. 查询结果集处理:DBUtils中最常用的工具类是QueryRunner,它支持执行SQL查询和更新操作。对于查询操作,QueryRunner可以将结果集转换为Bean对象列表,方便进行数据绑定和展示。例如,通过`QueryRunner.runQuery()...

    DBUtils数据库的使用

    SQLite支持多种常见的SQL语法,与DBUtils结合使用,可以轻松实现Java应用的数据持久化。 在"SQLiteDemo"这个文件中,可能包含了一个演示如何使用DBUtils与SQLite数据库交互的示例。通常,这样的示例会包括以下步骤...

    python的DBUtils包

    Python的DBUtils是一个非常实用的库,主要用于增强Python标准库中的`DB-API 2.0`接口,提供了线程安全性和连接池管理等功能。DBUtils是基于PEP 249设计的,它使得数据库连接的管理和维护变得更加简单,尤其在多线程...

    C3P0和DButils

    DBUtils的核心功能包括QueryRunner类,它支持预编译的SQL语句,可以有效防止SQL注入攻击。此外,DBUtils还提供了异常处理机制,使得数据库操作更加健壮。 将C3P0和DBUtils结合使用,可以构建一个高效且稳定的数据库...

    commons-dbutils-1.7

    3. **结果集处理**:DbUtils提供了处理结果集的便捷方式。例如,`ResultSetHandler`接口定义了如何将结果集转换为Java对象。有几种预定义的实现,如`BeanHandler`将结果集映射到单个Java Bean,`BeanListHandler`则...

    commons-dbutils.jar.rar

    DBUtils是一个实用程序库,它简化了JDBC(Java Database Connectivity)的使用,提供了更安全和易于管理的数据库访问方式。这个压缩包包括1.3、1.6和1.7三个版本,这些版本覆盖了从早期到较新的时期,以适应不同项目...

    DbUtils数据库查询工具包 v1.8.1.zip

    3. **DataSource**: DataSource是JDBC中用于获取数据库连接的接口,DbUtils支持任何实现了javax.sql.DataSource接口的数据源。你可以使用Apache Commons DBCP或C3P0等第三方数据源,也可以使用应用服务器提供的数据...

    DBUtils数据库工具类

    6. **批处理**:DBUtils支持批处理操作,可以通过`batchUpdate()`方法执行多条相同结构的SQL更新语句,提高数据库操作性能。 在实际开发中,使用DBUtils的步骤通常包括以下几步: 1. 配置数据库连接信息,如URL、...

    dbutils

    1. **批处理操作**:`dbutils` 支持批量执行SQL语句,可以显著提高数据库操作的性能,尤其在处理大量数据时。 2. **QueryRunner与ResultSetHandler**:`QueryRunner` 类是`dbutils` 的核心组件,它提供了一种简单的...

    DButils使用实例

    DButils支持批处理,通过`BatchRunner`类,可以方便地执行多条SQL语句的批量操作。这在插入大量数据或者进行重复操作时非常有用,因为它可以提高效率并减少与数据库的交互次数。 4. **异常处理** DButils将JDBC的...

    commons-dbutils-1.3.zip

    DBUtils库是Apache Commons项目的一部分,旨在提供一个简单、安全的方式来处理数据库操作,减少与数据库交互时出现的常见错误。 DBUtils的核心理念是基于数据库连接池和对JDBC API的封装,以提高性能和易用性。在...

    DBUtils jar包 官方原版的

    通过QueryRunner,你可以执行简单的SQL查询、插入、更新和删除操作,同时也支持预编译的PreparedStatement,防止SQL注入攻击。 3. **ResultHandler接口**:DBUtils提供了ResultHandler接口,用于自定义结果集处理...

    dbutils + oracle 增删改查批量插入示例

    Oracle支持复杂的SQL语法,如子查询、联接、视图等,这些都可以借助dbutils来执行。 4. **dbutils开发包及其源码**:开发者可以通过阅读源码来深入理解dbutils的工作原理,从而更好地利用其功能。源码提供了关于...

    DBUtils组件

    3. **结果集处理**:DBUtils支持多种结果集处理方式,如将结果集转换为单个对象、List对象、Map对象等。这使得数据获取更加灵活。 4. **异常处理**:DBUtils通过包装JDBC的SQLException,提供了更友好的异常处理...

Global site tag (gtag.js) - Google Analytics