spring-jdbc直接获得POJO对象

标准spring-jdbc JdbcTemplate提供了 queryForObject(sql, requiredType)方法,
也许你会认为,他会把 select name,id from usr 转换成包含name和id的 Usr 类,

但是只要你看一下他的源代码,就知道这只能是一种幻想
@Override
public <T> T queryForObject(String sql, Class<T> requiredType) throws DataAccessException {
return queryForObject(sql, getSingleColumnRowMapper(requiredType));
}

spring只能处理返回一个字段的SQL,那么只能针对String这类简单对象。

这个方法我个人觉得,很欠妥,对比一下.net中针对返回一条记录一个字段的情形
Object SqlCommand.ExecuteScalar()

这个方法多么清晰明确,返回的是一个标量,不是集合更不是列表,这种地方真心没必要用泛型。

而对于返回一个个性对象,mybatis中可以很简单实现,其实我们大可自己实现一个,没什么难的。

对于类
class Usr{
void setName(String s){}
void setId(int id){}
}

就可以简单使用下面方式
Usr u=myJdbcTemplate.getPOJO("select id,name from usr where id=?",Usr.class,1);
if(u==null){
//用户没找到
}

spring-jdbc还有一个问题,就是返回单记录的查询,如果不存在,会直接抛出异常,但是实际使用中,这种情况一般都是正常情况,
程序本来就要处理,这样就逼迫程序必须捕获异常,变得很难看。更糟糕的是,其内部实际都是先生成一个List,
然后检查是否只有一条记录,0或者>1全部要抛出异常。白白多生成一个List对象。这点对比.net的设计就知道差距了。


因此额外增加了一个getSingleMap方法
其他代码基本都是自解释的,无非根据jdbc返回记录的字段名,去对应class利用反射查询相应方法
可能需要改进的就是一些特殊的SQL字段类型需要单独处理一下。目前,字符串,整数,日期类型都没问题

public class myJdbcTemplate extends JdbcTemplate {
	
	/**获得单一map对象,不存在时返回null*/
	public Map<String, Object> getSingleMap(String sql, Object... args) throws DataAccessException{
		
        return this.query(sql, new ResultSetExtractor<Map<String ,Object>>(){

			public Map<String ,Object> extractData(ResultSet rs) throws SQLException,
					DataAccessException {
				if(!rs.next()) return null;
				
				return new ColumnMapRowMapper().mapRow(rs, 1);
			}
        }, args);
	}
	
	/**获得单一POJO对象,对应字段名存在1个参数的setXXX方法且字段值不为null时调用,不存在时返回null*/
	public <T> T getPOJO(String sql,final Class<T> t,Object... args){
        return this.query(sql, new ResultSetExtractor<T>(){

			public T extractData(ResultSet rs) throws SQLException,
					DataAccessException {
				if(!rs.next()) return null;
				
				ResultSetMetaData dd= rs.getMetaData();
				int count=dd.getColumnCount();
		
				return toPOJO(t,rs,dd,count);
				
			}
        }, args);
		
	}

	/**获得POJO对象List,对应字段名存在1个参数的setXXX方法且字段值不为null时调用*/
	public <T> List<T> getPOJOList(String sql,final Class<T> t,Object... args){
        return this.query(sql, new ResultSetExtractor<List<T>>(){

			public List<T> extractData(ResultSet rs) throws SQLException,
					DataAccessException {
				List<T> l=new ArrayList<T>();
				
				ResultSetMetaData dd= rs.getMetaData();
				int count=dd.getColumnCount();
				
				while(rs.next()) {
					T o=toPOJO(t,rs,dd,count);
					if(o==null) return null;
					l.add(o);
				}
				
				return l;
			}
        }, args);
		
	}
	
	//转换成 pojo
	private <T> T toPOJO(Class<T>t,ResultSet rs,ResultSetMetaData dd,int count) throws SQLException{
		T o;
		try {
			o =t.newInstance();
		} catch (InstantiationException e) {
			logger.error("getPOJO InstantiationException when new "+t.getName());
			return null;
		} catch (IllegalAccessException e) {
			logger.error("getPOJO IllegalAccessException when new "+t.getName());
			return null;
		}
		
		for (Method m : t.getMethods()){
			String ms=m.getName();
			if (!ms.startsWith("set") || m.getParameterTypes().length!=1 ) continue;
		
			ms=ms.substring(3).toLowerCase();
			for(int i=1;i<=count;i++){
				if (!dd.getColumnLabel(i).toLowerCase().equals(ms)) continue;
				
				Object a=rs.getObject(i);
				if (a==null) break;
				
				try {
					m.invoke(o, a);
				} catch (IllegalAccessException e) {
					logger.error("getPOJO IllegalAccessException when "+m.getName());
					return null;
				} catch (IllegalArgumentException e) {
					logger.error("getPOJO IllegalArgumentException when "+m.getName());
					return null;
				} catch (InvocationTargetException e) {
					logger.error("getPOJO InvocationTargetException when "+m.getName());
					return null;
				}
				break;
			}
		}
		return o;
		
	}
}


有了这个方法,使用mybatis的理由就又少了一个。

版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值