论坛首页 Java企业应用论坛

请点评jdbc通用访问方法,这样可行吗?

浏览 16352 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (2) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-08-20  
OO
    最近在检查其他同事写的代码,看到一同学写的了一个通用JDBC模板(静态工厂模式),似乎没有什么问题,但看起来很是不美观,有点怪异的感觉。我想了很久是不是要在论坛中发布,我觉得这样的代码还是不够OO,为什么自己对应的域对象操作不直接用用对象封装来处理呢?而转用ResultSetMetaData来解析对应的字段的属性,而且每次要把相关的参数保存到MAP、list中,然后又要取出来解析。所以我觉得回影响性能。当然在测试过程中没有发现性能的问题。由于项目中其他同学也在用他这个模板,他们觉得很方便。但对应新人(刚毕业的同学)来说,经常在调试的时候发生了错误,都不知错误发生在那?导致又要其他同学帮忙,乱费太多时间,而且他们还是不知其所以然。请大家帮忙评点一下。谢谢!
//通过SQL反回对应的数据集
//比如:sql select nameSc,age from users
public List getResultDataList(String sql, Connection con) {
		List<Map> dataList = new ArrayList<Map>();
		Map<String, String> map = new HashMap<String, String>();//存放对应字段数据
		PreparedStatement ps = null;
		ResultSet ds = null;
		ResultSetMetaData rsd;
		try {
			ps = con.prepareStatement(sql);
			ds = ps.executeQuery();
			while (ds.next()) {
				map = new HashMap<String, String>();//通过键值对存放一条记录的数据
				rsd = ds.getMetaData();
				for (int i = 1; i <= rsd.getColumnCount(); i++) {
					switch (rsd.getColumnType(i)) {//通过判断数据类型转换数据
					case 12:// varchar(12)
						map.put(rsd.getColumnName(i), ds.getString(i));
						break;
					case 1:// char(1)
						map.put(rsd.getColumnName(i), ds.getString(i));
						break;
					case -7:// bit(-7)
						map.put(rsd.getColumnName(i), Boolean.toString(ds
								.getBoolean(i)));
						break;
					case 4:// int(4)
						map.put(rsd.getColumnName(i), Integer.toString(ds
								.getInt(i)));
						break;
					case 5:// smallint(5)
						map.put(rsd.getColumnName(i), Integer.toString(ds
								.getInt(i)));
						break;	
					case 93:// datetime(93)
						if (ds.getString(i) == null)
							map.put(rsd.getColumnName(i), "");
						else {
							if (ds.getString(i).length() >= 19) {
								map.put(rsd.getColumnName(i), ds.getString(i)
										.substring(0, 19));
							} else {
								map.put(rsd.getColumnName(i), ds.getString(i)
										.substring(0, 10));
							}
						}
						break;
					case 3:// decimal(3)
						map.put(rsd.getColumnName(i), Double.toString(ds
								.getDouble(i)));
						break;
					default:
						map.put(rsd.getColumnName(i), ds.getString(i));
						break;
					}
				}
				dataList.add( map);//存放所有行数据
			}
		} catch (SQLException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		} finally {
                        [color=red]connection是通过HibernateDaoSupport获取得到的,似乎能够自动回收(反回到连接池),是否真的不用关闭连接呢?[/color]
			/*
			 * try{ if(ds!=null){ds.close();ds=null;}
			 * if(ps!=null){ps.close();ps=null;}
			 * if(con!=null){con.close();con=null;} }catch(SQLException e){}
			 */
		}
		return dataList;
	}



//通过传递SQL,Sql的参数更新数据
//比如 sql insert into users(nameCs,age)valuse(?,?)
//params就是存放?代表的值
public int execUpdateByParams(String sql, Connection con, List params) {
		PreparedStatement ps = null;
		int message = 0;
		try {
			String paramsStr="";
			ps = con.prepareStatement(sql);
			if (params != null) {
				for (int i = 0; i < params.size(); i++) {
					String p = params.get(i)==null?null:"" + params.get(i);//设置对应的参数
					ps.setString(i + 1, p);
				}
			}
			ps.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
			message = -1;
			throw new RuntimeException(e);
		} finally {
			try {
				if (ps != null) {
					[color=red]ps.close();[/color]//怎么在这他有把这个关闭了呢?这会有问题吧?
					ps = null;
				}
				// if(con!=null){con.close();con=null;}
			} catch (SQLException e) {
			}
		}

		return message;
	}
   发表时间:2008-08-22  
以前我在公司培训的时候,也做过类似的程序,初看起来,很似好用。但是其实有一个很典型的问题,如果数据库有一个BLOB数据类型的怎么办?如果使用了不同的数据库,存在了另外的数据类型怎么办?

当时想了想,姑且不管什么OO,单就扩展性方面,就比较差。
这个问题提出来了,正好也关注下
0 请登录后投票
   发表时间:2008-08-22  
使用这个
Map<String, String> map = new HashMap<String, String>();//存放对应字段数据
当然是不通用
换成
Map<String, Object> map = new HashMap<String, Object>()
还好一些

0 请登录后投票
   发表时间:2008-08-22  
没有什么可不可行,能解决问题就行,当然看起来的确不那么自然美观
0 请登录后投票
   发表时间:2008-08-23  
kunanfo 写道
以前我在公司培训的时候,也做过类似的程序,初看起来,很似好用。但是其实有一个很典型的问题,如果数据库有一个BLOB数据类型的怎么办?如果使用了不同的数据库,存在了另外的数据类型怎么办?

当时想了想,姑且不管什么OO,单就扩展性方面,就比较差。
这个问题提出来了,正好也关注下

数据类型和移值性和扩展性确实不好。
移值性就不说了,因为我们很长一段时间都会定位在SQL SERVER上。
BLOB这个也不会了,因为有对立的文件服务器。
0 请登录后投票
   发表时间:2008-08-23  
stworthy 写道
使用这个
Map<String, String> map = new HashMap<String, String>();//存放对应字段数据
当然是不通用
换成
Map<String, Object> map = new HashMap<String, Object>()
还好一些


恩,确实会好点。那个SQL一般都处理了。查询出来的数据最终只是显示在页面上,问题不大。
1 请登录后投票
   发表时间:2008-08-23  
HRoger 写道
没有什么可不可行,能解决问题就行,当然看起来的确不那么自然美观

要多次的转换,应该对性能会有影响的
0 请登录后投票
   发表时间:2008-08-23  
javaXX 写道
你传入的SQL语句 我建议不如用 Ognl,参数再加个POJO类代表一张表,和他的类型,直接将查到的数据放进去,这样是不是比较像ORM了!!

其实,同事的思想是用MAP来封装数据。
0 请登录后投票
   发表时间:2008-08-23  
getResultDataList 这个方法封装思路还是可取的,足够解决很大一部分的应用场景(不要期望有一个牛x的方法就可以搞定所有应用场景)。但是代码实现却比较糟糕。

首先如果返回是String类型的字段值,是根本不需要判断字段的类型,所以代码里那些case是没必要,
其次,既然用到了case,所有了、的类型值,在SqlType里已经定义为常量,这里不应该再写成 case 1,2,3,4这样的方式。
还有最后的finally里的一个try进行三个关闭,存在严重的隐患。

总之,建议如楼上所说,这些代码封装其实都有现成的。Apache common DBUtils已经封装得很好了。

0 请登录后投票
   发表时间:2008-08-23  
to codeutil
非常感谢你的建议。
其实我们用了HIBERNATE,但项目比较大,时间比较赶,而且其他同学学习的不够好(我也差不多),我才决定不会用hibernate的就用jdbc,任其他们天马行空,可谓写的奇特。性能问题很快就冒出来了。

“finally里的一个try进行三个关闭,存在严重的隐患。”我们用HibernateDaoSupport管理连接的,我们都不用手动关闭了吧?,那些都注释了。
0 请登录后投票
论坛首页 Java企业应用版

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