让JAVA的JDBC支持命名参数的SQL语句

  JAVA 的JDBC连接数据库时,传递参数的方式是通过索引位置实现(根据SQL中?号出现的顺序,例如 SELECT * FROM [table] WHERE [name] =? OR [title]=?);这让使用SQL语句变得比较麻烦也不符合使用习惯。

  为此专门创建了一个类NSQL用于支持命名方式给SQL语句传递参数(例如 SELECT * FROM [table] WHERE [name] =?name OR [title]=?title)。其基本原理是,以?号为参数标识,后跟参数名称,在编写SQL语句时候采用命名参数方式,然后由NSQL类将其分析后生成JDBC可用的基于?号顺序的SQL语句,同时记录参数顺序。这样既可实现命名参数的SQL语句。

  代码如下所示:

/**
 * 2017年2月16日
 */
package com.kiy.service.data;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * SQL语句抽象,提供基于命名参数的SQL语句功能
 * 
 * @author Simon(ZhangXi)
 *
 */
public final class NSQL {

	// 静态集合缓存使用过的NSQL
	private static Map<String, NSQL> caches = new ConcurrentHashMap<String, NSQL>();

	private String sql_naming;
	private String sql_execute;
	private String[] names;

	private NSQL() {
		// 用户不能实例化对象
		// 通过get方法获取可用实例
	}
	
	public boolean hasName() {
		return names.length > 0;
	}

	public void setParameter(PreparedStatement ps, String name, Object value) throws SQLException {
		for (int a = 0, b = names.length - 1; a <= b; a++, b--) {
			if (names[a].equals(name)) {
				ps.setObject(a + 1, value);
			}
			if (a != b && names[b].equals(name)) {
				ps.setObject(b + 1, value);
			}
		}
	}

	public void setParameters(PreparedStatement ps, Map<String, Object> values) throws SQLException {
		for (int index = 0; index < names.length; index++) {
			ps.setObject(index + 1, values.get(names[index]));
		}
	}

	/**
	 * 获取用于数据库执行的SQL语句
	 * 
	 * @return
	 */
	public String getSql() {
		return sql_execute;
	}

	/**
	 * 获取用户定义的命名SQL语句
	 * 
	 * @return
	 */
	public String getNamingSql() {
		return sql_naming;
	}

	/**
	 * 获取对象实例,此方法将缓存分析过的SQL语句以提高性能
	 * 
	 * @param sql
	 * @return
	 */
	public static NSQL get(String sql) {
		NSQL nsql = caches.get(sql);
		if (nsql == null) {
			nsql = NSQL.parse(sql);
			caches.put(sql, nsql);
		}
		return nsql;
	}

	/**
	 * 分析命名SQL语句获取抽象NSQl实例;java(JDBC)提供SQL语句命名参数而是通过?标识参数位置,
	 * 通过此对象可以命名参数方式使用SQL语句,命名参数以?开始后跟名称?name。
	 * 例如:SELECT * FROM table WHERE name = ?key AND email = ?key;
	 * 
	 * @param sql
	 * @return
	 */
	public static NSQL parse(String sql) {
		// SELECT * FROM table WHERE name = ?key AND email = ?key;
		// A~Z a~z 01~9 _
		if (sql == null)
			throw new NullPointerException("SQL String is null");

		char c;
		List<String> names = new ArrayList<String>();
		StringBuilder sql_builder = new StringBuilder();
		StringBuilder name_builder = new StringBuilder();
		for (int index = 0; index < sql.length(); index++) {
			c = sql.charAt(index);
			sql_builder.append(c);
			if ('?' == c) {
				while (++index < sql.length()) {
					c = sql.charAt(index);
					if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9')) {
						name_builder.append(c);
					} else {
						sql_builder.append(c);
						break;
					}
				}
				names.add(name_builder.toString());
				name_builder.setLength(0);
			}
		}
		NSQL dbsql = new NSQL();
		dbsql.sql_naming = sql;
		dbsql.sql_execute = sql_builder.toString();
		dbsql.names = names.toArray(dbsql.names = new String[names.size()]);
		return dbsql;
	}

	public String toString() {
		return "NAMING: " + sql_naming + "\nEXECUTE: " + sql_execute;
	}
}

    NSQL类的使用如下所示:

public boolean CreateUser(User u) {
		NSQL sql1 = NSQL.get("INSERT INTO `users` (`id`,`name`,`password`,`enable`,`realname`,`mobile`,`phone`,`email`,`remark`,`created`,`updated`) VALUES (?id,?name,?password,?enable,?realname,?mobile,?phone,?email,?remark,?created,?created)");

		Connection connection = dbc.get();
		try (PreparedStatement s1 = connection.prepareStatement(sql1.getSql())) {
			sql1.setParameter(s1, "id", u.getId());
			sql1.setParameter(s1, "name", u.getName());
			sql1.setParameter(s1, "password", u.getPassword());
			sql1.setParameter(s1, "enable", u.getEnable());
			sql1.setParameter(s1, "realname", u.getRealname());
			sql1.setParameter(s1, "mobile", u.getMobile());
			sql1.setParameter(s1, "phone", u.getPhone());
			sql1.setParameter(s1, "email", u.getEmail());
			sql1.setParameter(s1, "remark", u.getRemark());
			sql1.setParameter(s1, "created", u.getCreated());
			return s1.executeUpdate() == 1;
		} catch (SQLException ex) {
Log.error(ex);
return false;
 } finally {
dbc.put(connection);
}

如此即可通过命名方式使用SQL语句了,欢迎大家多多交流。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值