论坛首页 Java企业应用论坛

jdbc通用查询通过map替代实体

浏览 8930 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (2) :: 隐藏帖 (0)
作者 正文
   发表时间:2012-10-15   最后修改:2012-10-15

发此贴是请大家互相探讨,交流,无聊人事请提前走远。

 

从10年做一个项目时,由于项目中需要做大量的查询功能,所以觉得如果使用传统的方式去做查询的话,就需要构建很多实体,比较繁琐,而且我们项目的特征是只需要做查询,不需要做新增,修改等操作,所以对此我写了一个公共类来处理此问题。

传统方式:传入sql,返回结果集,然后便利结果集封装实体List。

我的方式:传入sql,返回List。List中装的是map,而map中的key对应sql中的列,map中的value对应列的值。

备注:由于部分代码牵扯到公司的一些公共包(不方便发出),所以代码不能直接运行,请大家下载代码后做相应的改动,请谅解。如需我提供可直接运行的实例,请回复此贴联系我。

代码有问题的请批评指正。

 

主要代码:

 

import java.math.BigDecimal;
import java.sql.Clob;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @描述:利用jdbc进行常见的查询
 * @author richersky
 * @日期:2010-06-27
 */
public class EntityDaoImplJdbc {
	
	private String datasourse;
	
	/**
	 * 根据sql语句查询数据
	 * @param sql
	 * @param page
	 * @return
	 * @throws Exception
	 */
	public Page findSql(String sql, Page page) throws Exception{
		JdbcUtil jdbcUtil = null;
		try {
			StringBuffer ssql = new StringBuffer();
			ssql.append(sql);
			//获取条件对应的值集合
			List valueList = page.getValues();
			LogUtil.infoSql(EntityDaoImplJdbc.class,valueList,"SQL语句:",ssql.toString());
			jdbcUtil = new JdbcUtil(datasourse);
			PreparedStatement preparedStatement = jdbcUtil.createPreparedStatement(ssql.toString());
			int liSQLParamIndex = 1;
			if(valueList!=null){
				for(int i=0;i<valueList.size();i++){
					Object obj = valueList.get(i);
					this.setParameterValue(preparedStatement, i+1, obj);
					liSQLParamIndex++;
				}
			}
			
			ResultSet rs = preparedStatement.executeQuery();
			List<Map<String,Object>> dataList = new ArrayList<Map<String,Object>>();
			Map<String,Integer> metaDataMap = null;
			while(rs.next()){
				if(rs.isFirst()){
					metaDataMap = this.getMetaData(rs);
				}
				dataList.add(this.setData(rs,metaDataMap));
			}
			page.setDataList(dataList);
		}catch (Exception e) {
			LogUtil.error(this.getClass(), e,"利用jdbc进行查询时出错!");
			throw e;
		}finally{
			if(jdbcUtil!=null){
				jdbcUtil.freeCon();
			}
		}
		return page;
	}
	
	/**
	 * 根据sql查询出单条记录
	 * @param sql
	 * @return Map<String,Object>
	 * @throws Exception 
	 */
	public Map<String,Object> findUniqueBySql(String sql,List<Object> valueList) throws Exception{
		JdbcUtil jdbcUtil = null;
		Map<String,Object> map = null;
		try {
			LogUtil.infoSql(EntityDaoImplJdbc.class,valueList,"SQL语句:",sql);
			jdbcUtil = new JdbcUtil(datasourse);
			PreparedStatement preparedStatement= jdbcUtil.createPreparedStatement(sql);
			if(valueList!=null){
				for(int i=0;i<valueList.size();i++){
					Object obj = valueList.get(i);
					this.setParameterValue(preparedStatement, i+1, obj);
				}
			}
			ResultSet rs = preparedStatement.executeQuery();
			Map<String,Integer> metaDataMap = null;
			if(rs.next()){
				metaDataMap = this.getMetaData(rs);
				map = this.setData(rs,metaDataMap);
			}
		}catch (Exception e) {
			LogUtil.error(this.getClass(), e,"利用jdbc进行查询时出错!");
			throw e;
		}finally{
			if(jdbcUtil!=null){
				jdbcUtil.freeCon();
			}
		}
		return map;
	}
	
	/**
	 * 设置PreparedStatement预处理sql语句的值
	 * @param pStatement
	 * @param piIndex
	 * @param pValueObject
	 * @throws Exception
	 */
	private void setParameterValue(PreparedStatement pStatement, int piIndex,Object pValueObject) throws Exception {
		if (pValueObject instanceof String) {
			pStatement.setString(piIndex, (String) pValueObject);
		} else if (pValueObject instanceof Boolean) {
			pStatement.setBoolean(piIndex, ((Boolean) pValueObject).booleanValue());
		} else if (pValueObject instanceof Byte) {
			pStatement.setByte(piIndex, ((Byte) pValueObject).byteValue());
		} else if (pValueObject instanceof Short) {
			pStatement.setShort(piIndex, ((Short) pValueObject).shortValue());
		} else if (pValueObject instanceof Integer) {
			pStatement.setInt(piIndex, ((Integer) pValueObject).intValue());
		} else if (pValueObject instanceof Long) {
			pStatement.setLong(piIndex, ((Long) pValueObject).longValue());
		} else if (pValueObject instanceof Float) {
			pStatement.setFloat(piIndex, ((Float) pValueObject).floatValue());
		} else if (pValueObject instanceof Double) {
			pStatement.setDouble(piIndex, ((Double) pValueObject).doubleValue());
		} else if (pValueObject instanceof BigDecimal) {
			pStatement.setBigDecimal(piIndex, (BigDecimal) pValueObject);
		} else if (pValueObject instanceof Date) {
			pStatement.setDate(piIndex, (Date) pValueObject);
		} else if (pValueObject instanceof Time) {
			pStatement.setTime(piIndex, (Time) pValueObject);
		} else if (pValueObject instanceof Timestamp) {
			pStatement.setTimestamp(piIndex, (Timestamp) pValueObject);
		} else {
			pStatement.setObject(piIndex, pValueObject);
		}
	}

	/**
	 * 根据传入的结果集返回结果集的元数据,以列名为键以列类型为值的map对象
	 * @param rs
	 * @return 
	 * @throws SQLException
	 */
	private Map<String,Integer> getMetaData(ResultSet rs) throws SQLException{
		Map<String,Integer> map = new HashMap<String,Integer>();
		ResultSetMetaData metaData = rs.getMetaData();
        int numberOfColumns =  metaData.getColumnCount();
        for(int column = 0; column < numberOfColumns; column++) {
        	String columnName = metaData.getColumnLabel(column+1);
        	int colunmType = metaData.getColumnType(column+1);
        	columnName = columnName.toLowerCase();
            map.put(columnName, colunmType);
        }
        return map;
	}
	
	/**
	 * 将结果集封装为以列名存储的map对象
	 * @param rs
	 * @param metaDataMap元数据集合
	 * @return
	 * @throws Exception
	 */
	private Map<String,Object> setData(ResultSet rs,Map<String,Integer> metaDataMap) throws Exception {
		Map<String,Object> map = new HashMap<String,Object>();
		for (String columnName : metaDataMap.keySet()) {
			int columnType = metaDataMap.get(columnName);
			Object object = rs.getObject(columnName);
			if(object==null){
				map.put(columnName, null);
				continue;
			}
			//以下并为对所有的数据类型做处理,未特殊处理的数据类型将以object的形式存储。
			switch (columnType) {
			case java.sql.Types.VARCHAR:
				map.put(columnName, object);
				break;
			case java.sql.Types.DATE:
				map.put(columnName, DateUtil.format(object.toString()));
				break;
			case java.sql.Types.TIMESTAMP:
				map.put(columnName, DateUtil.format(object.toString()));
				break;
			case java.sql.Types.TIME:
				map.put(columnName, DateUtil.format(object.toString()));
				break;
			case java.sql.Types.CLOB:
				try{
					if(object!=null){
						Clob clob = (Clob)object;
						long length = clob.length();
						map.put(columnName, clob.getSubString(1L, (int)length));
					}
				}catch(Exception e){
					LogUtil.error(this.getClass(), e,"将字段值从clob转换为字符串时出错@!");
				}
				break;
			case java.sql.Types.BLOB:
				map.put(columnName, "");
				break;
			default:
				map.put(columnName, object);
				break;
			}
		}
        return map;
	}
}
   发表时间:2012-10-15  
可以的,我们工程有一个查询的模块,也是基本不涉及到修改,所以也用的MAP,如果需要业务方面的处理,可以根据不同的功能再写一些方法对MAP里的数据进行处理。觉得用起来还是挺顺手的,尤其是新增一个新的查询功能时很方便。
0 请登录后投票
   发表时间:2012-10-16  
楼主这种情况直接用JDBC的RowSet就好了,何苦还要自己转换成Map


Java 5在Java Database Connectivity (JDBC)方面加强了支持,其中加入了新的包javax.sql.rowset,javax.sql.rowset.serial,javax.sql.rowset.spi。从RowSet接口继承规定了五个新的接口:

1. CachedRowSet: CachedRowset可以不用与数据源建立长期的连接,只有当从数据库读取数据或是往数据库写入数据的时候才会与数据库建立连接,它提供了一种轻量级的访问数据库的方式,其数据均存在内存中。

2. JdbcRowSet:对ResultSet的对象进行包装,使得可以将ResultSet对象做为一个JavaBeans ™ 组件。

3. FilteredRowSet:继承自CachedRowSet,可以根据设置条件得到数据的子集。

4. JoinRowSet:继承自CachedRowSet,可以将多个RowSet对象进行SQL Join语句的合并。

5. WebRowSet:继承自CachedRowSet,可以将WebRowSet对象输出成XML格式。
0 请登录后投票
   发表时间:2012-10-16  
回复:方世玉
兄弟这种方式在db层确实没有问题,但是如果直接把rowset返回给action,那么action是不是仍然需要在解析然后封装数据,在返回给页面啊。
0 请登录后投票
   发表时间:2012-10-16  
使用 dbutils,用 MapListHandler 得到的就是 List<Map<String, Object>>
0 请登录后投票
   发表时间:2012-10-16  
若使用Spring JDBC,则可以直接使用“jdbcTemplate.queryForMap(sql);”

不过个人觉得,这种查询比较简单。遇到相对复杂的报表就无能为力了,所以还是使用报表

工具开发比较快。
0 请登录后投票
   发表时间:2012-10-16  
richer 写道
回复:方世玉
兄弟这种方式在db层确实没有问题,但是如果直接把rowset返回给action,那么action是不是仍然需要在解析然后封装数据,在返回给页面啊。

为什么给页面的一定要是Map呢?Rowset一样可以给页面啊。
特别是WebRowSet可以很方便的转成xml,可以很容易的和Javascript写的Datagrid控件配合啊
0 请登录后投票
   发表时间:2012-10-18   最后修改:2012-10-18
有个90%查询项目,用IBATIS
输入用Map,入参数多少都可以
输出定义返回成Map或者listMap,Map的key就为列名
剩下的就是写sql了,结合struts2,页面标签直接从listMap中获取数据展示

DAO
public List<Map<String, Object>> queryForList(Map map) {
return this.getSqlMapClientTemplate().queryForList(
map.get("statementName").toString(), map);
}

struts2 jsp
<ul class="clearfix">
<s:iterator value="listMap">
<li>
                    <s:property value="ID"/>:<s:property value="NAME"/>
</li>
</s:iterator>
</ul>

ibatis.xml
<select id="dataInfo" parameterClass="java.util.HashMap"
resultClass="java.util.HashMap">
select ID, NAME
  from TB_FACT_FAV
where id = #id#
</select>
0 请登录后投票
   发表时间:2012-10-23  
方世玉 写道
richer 写道
回复:方世玉
兄弟这种方式在db层确实没有问题,但是如果直接把rowset返回给action,那么action是不是仍然需要在解析然后封装数据,在返回给页面啊。

为什么给页面的一定要是Map呢?Rowset一样可以给页面啊。
特别是WebRowSet可以很方便的转成xml,可以很容易的和Javascript写的Datagrid控件配合啊


我那个说法不太严谨。由于我们团队的前台并不是现在主流的ext或者其它之类的框架,而是原始的html,所以我们解析后台传递数据时,还用的是struts标签或者是jstl标签。呵呵。我可能只是站在了我们的立场上考虑了下,所以没说清楚。
0 请登录后投票
   发表时间:2012-10-23  
wangchengyong 写道
有个90%查询项目,用IBATIS
输入用Map,入参数多少都可以
输出定义返回成Map或者listMap,Map的key就为列名
剩下的就是写sql了,结合struts2,页面标签直接从listMap中获取数据展示

DAO
public List<Map<String, Object>> queryForList(Map map) {
return this.getSqlMapClientTemplate().queryForList(
map.get("statementName").toString(), map);
}

struts2 jsp
<ul class="clearfix">
<s:iterator value="listMap">
<li>
                    <s:property value="ID"/>:<s:property value="NAME"/>
</li>
</s:iterator>
</ul>

ibatis.xml
<select id="dataInfo" parameterClass="java.util.HashMap"
resultClass="java.util.HashMap">
select ID, NAME
  from TB_FACT_FAV
where id = #id#
</select>

1、不是所有的sql IBATIS 都可以解析的。起码我们遇到过ejb都无法解析的sql。所以在迫于时间的压力下,我们没有找其他更好的框架,选择了用jdbc来做查询。
2、公司都有自己成熟的一套东西了嘛。哪能说改就同意让你去改啊。公司平台中就提供了ejb和jdbc原生2种方式。不得已的情况下选择了jdbc原生的查询,所以做了上文中的扩展。

呵呵,我没把我们当时的处境描述清楚。失误失误。不过你说的这种方式确实很适用于我们这种情况。谢谢你的建议。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics