/***********本人原创,欢迎转载,转载请保留本人信息*************/
/***********文章发表请与本人联系,作者保留所有权利*************/
作者:wallimn
电邮:
[email protected]
博客:
http://blog.csdn.net/wallimn
网络硬盘:
http://wallimn.ys168.com
时间:2009-01-06
/***********本人原创,欢迎转载,转载请保留本人信息*************/
/***********文章发表请与本人联系,作者保留所有权利*************/
引言
所谓命名参数,使用.net的人应该比较熟,很方便,参数多的时候不容易出错,搞不懂java为什么就不支持。如果没有使用过,或者对于命名参数不知所云,请看下面的说明。
PreparedStatement中参数都是使用下标传值,如:
- PreparedStatement p = con.prepareStatement("select * from people where
- (first_name = ? or last_name = ?) and address = ?");
- p.setString(1, name);
- p.setString(2, name);
- p.setString(3, address);
但是如果查询语句复杂,或者修改了sql,要跟踪每个参数的下标将变得非常麻烦并且容易出错,如果使用名称来命名参数就可以解决这个问题,如:
- PreparedStatement p = con.prepareStatement("select * from people where
- (first_name =:name or last_name =:name) and address =:address");
- p.setString("name", name);
- p.setString("address", address);
正文
最近认真学习了一下正则表达式,发现使用正则表达式可以很好的解决这个问题。
思路如下:
以命名参数的形式写好SQL语句,然后使用正则表达式提取出所有参数,使用Map记录,然后将参数替换成?(也就是java要求的标准形式),使用标准的SQL语句来创建PreparedStatement,最后根据Map来设置PreparedStatement的参数。
好了,废话少说。贴一下代码,我个人觉得实现的比较得比较简单、优雅。没有仔细测试,如发现问题,欢迎交流(
[email protected])。
- import java.sql.PreparedStatement;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.Map.Entry;
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- public class NamedParamSqlUtil {
- static final Log log = LogFactory.getLog(NamedParamSqlUtil.class);
- private Map paramsMap=new HashMap();
-
- public Map getParamsMap(){
- return paramsMap;
- }
- public void emptyMap(){
- paramsMap.clear();
- }
-
- public String parseSql(String sql) {
- String regex = "(:(//w+))";
- Pattern p = Pattern.compile(regex);
- Matcher m = p.matcher(sql);
- emptyMap();
- int idx=1;
- while (m.find()) {
-
- paramsMap.put(new Integer(idx++), m.group(2));
-
- }
- String result = sql.replaceAll(regex, "?");
- log.debug("分析前:"+sql);
- log.debug("分析后:"+result);
- return result;
- }
-
- public boolean fillParameters(PreparedStatement pStat,Map pMap){
- boolean result=true;
- String paramName=null;
- Object paramValue=null;
- int idx=1;
- for(java.util.Iterator> itr = paramsMap.entrySet().iterator(); itr.hasNext();){
- Entry entry = (Entry)itr.next();
- paramName = entry.getValue();idx=pMap.getKey().intValue;
-
- paramValue = pMap.get(paramName);
- try {
-
- pStat.setObject(idx, paramValue);
- } catch (Exception e) {
- log.error("填充参数出错,原因:"+e.getMessage());
- result=false;
- }
- }
- return result;
- }
- }
使用上面的类的方法如下:
- public boolean dbInserUpDe(Connection conn, String pSql,
- Map pMap) {
- if (pSql == null || "".equals(pSql)) {
- log.error("SQL语句错误!");
- return false;
- }
- boolean result = false;
- NamedParamSqlUtil util = new NamedParamSqlUtil();
- String sql = util.parseSql(pSql);
- try {
- PreparedStatement stat = conn.prepareStatement(sql);
- util.fillParameters(stat, pMap);
- result = stat.execute();
- } catch (Exception e) {
- log.error(e.getMessage());
- return false;
- }
- return result;
- }
后记
使用Map来传递参数是个很好的办法,比较便于封装,而且使用过Struts2.0的人都知道,Struts2.0自动的把ServletRequest中的参数提取到了Map中,使用以上方法十分的方便。如果不使用Struts2.0,也可以使用一个循环很方便的把ServletRequest中的参数提取的Map中。
另外,如果参数中有要求Date等类型时,要自行进行转化。字符串不用转换;数字类型在使用Oracle的情况下也不用转换(以字符串的形式传递数字类型,Oracle可以自动进行转换)。其它数据库不太了解。
/***********本人原创,欢迎转载,转载请保留本人信息*************/
/***********文章发表请与本人联系,作者保留所有权利*************/
作者:wallimn
电邮:
[email protected]
博客:
http://blog.csdn.net/wallimn
网络硬盘:
http://wallimn.ys168.com
时间:2009-01-06
/***********本人原创,欢迎转载,转载请保留本人信息*************/
/***********文章发表请与本人联系,作者保留所有权利*************/