`
hgq0011
  • 浏览: 553535 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

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

    博客分类:
  • Jdbc
阅读更多
    最近在检查其他同事写的代码,看到一同学写的了一个通用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;
	}
分享到:
评论
35 楼 fangwei 2009-08-12  
好处是封装了ResultSet的操作,直接映射成List<Map>
缺点是上层调用时需要看具体的sql才能知道Map里面是什么东东

ps:我维护过两年的一个系统就是这么干的,完全不需要javabean这种东东,不管在service层还是action层还是jsp直接map.get("xxx"),类少了很多,但是维护起来很不方便,后来在我的建议下增加了javabean,增加了一层对map的包装
34 楼 fjlyxx 2008-12-02  
说实话很不好!我了省事情把整个安全性给破坏了.也许这么说有点过分,但确实是这样的.

提几个意见
第一 注意分析切面,不该设置切面的地方不要这么做
第二 像数据库连接这种东西在小系统下也许不会体现它安全方面的重要性,但是你这么写的后果只会给连接丢失更多的机会.

我个人觉得数据库的切面应该是做在连接获取这块的,获取结果和数据更新操作虽然也可以 但是放置的地方和调用的地方要正确,我不赞同主动去调用这个模块 更赞同的是靠回调去注入连接,回调接口里面爱干嘛就干嘛了.

对于你的解析那块 还有很大的改进余地.不要case了 定义一个解析接口,系统维护一个数据库实际字段类型和RS解析类的映射 动态去调用.
就像

数据库字段A 用JAVA的类 com.xxxx.xxx去解析一样.当然你这个com.xxxx.xxx是你解析接口的一个实现. 这样做的好处是扩展性好而且可以对其他数据库进行支持
个人意见
33 楼 firmgoal 2008-10-01  
看Spring的JdbcTemplate吧,无论连接的获取、关闭,操作的灵活性,ResultSet的Mapping,都是上上之码。
32 楼 coreymylife 2008-09-29  
没认真看,但是认为这段代码极端的丑陋
#    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; 
31 楼 fuwang 2008-09-18  
你们这样把hibernate和jdbc混用了,如何共用连接池、连接何时关闭?事务等方面如何处理?
30 楼 starse7en77 2008-09-13  
编码就是为了解决问题 , 过多的考虑那些不实际的扩展是没意义的 。

诸如楼主这样 , 适用就好 。
29 楼 starse7en77 2008-09-13  
kunanfo 写道
以前我在公司培训的时候,也做过类似的程序,初看起来,很似好用。但是其实有一个很典型的问题,如果数据库有一个BLOB数据类型的怎么办?如果使用了不同的数据库,存在了另外的数据类型怎么办?

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


很简单发现有BLOB就不要用这方法 。
28 楼 vicksong 2008-09-02  
其实我一直是用这种方法,但你这种封装太简单了,用于商业的话太简单。太多的问题没有考滤到。比如在tolist中的,并不是每个数据都是从数据库中直接取出来的,有可以要计算或有可能要再进一步再查询等等情况,保存与更新的情况,没有考滤到的情况就更多了,好在,所有情况我基本都考滤到了,所有我用于商业了,说到性能,其实,软件性能主要体现还是在网络上。
27 楼 hlydlp 2008-09-01  
其实这样做也是一种办法,通用型比较好
26 楼 yefeng 2008-08-29  
直接用apache-dbutils好了,已经做了很好的封装了,性能也不会有问题
25 楼 armorking 2008-08-28  
public List getResultDataList(String sql, Connection con)
方法是传入一个不带参数的完整的sql,
这里存在两个问题
1、对于需要传入参数的情形,只能在调用前手动把参数值拼到sql文当中,这种做法无法防范sql注入攻击
如果万一有一天客户要求你们把这个缺陷给改正的话,估计会有人哭得很惨

2、同样是因为手动把参数值拼到sql文当中,
那么,即便前后的sql文除了参数值完全一样
因为
ps = con.prepareStatement(sql);
这一句里传入的sql文是不同的
所以,db端每次都要重新编译sql文
所以,在批量插入,更新,删除的时候会有性能问题
24 楼 dzmonkey 2008-08-28  
代码写的却是有些不合理的地方。
但是目的本身是值得提倡的,我不赞同那种做一个所谓的“工具”,就一定要面面俱到,考虑了所有情况,我觉得还是要立足于项目或项目组本身,自己够用就好,不需要上岗上线的评论他的美丽与丑陋。
总之,首先要适用,再次要能用,最后在考虑可能的扩展性等等。
23 楼 elvewyn 2008-08-28  
恨死Map了。如果不是自己的程序。都不知道他里面装的是啥类型的。我觉得如果说通用的话,做到ibatis\spring jdbc那种层次就非常不错了。
22 楼 greens.leaf 2008-08-26  
看是不是适合你的应用环境。

这种处理适用于你有很多表,对每个表的操作都不复杂,表之间的关系也不复杂的情况。

关于connetion和statement的资源释放,基本的原则是谁申请谁释放。
connection对象是从函数体外通过参数传入的,那么在函数体内不应该关闭,试想如果你的代码这样调用:
getResultDataList("sql1",conn);
getResultDataList("sql2",conn);
第二次调用函数会抛出空指异常。

反过来,statement对象是在函数体内通过connection.createStatement()创建的,那么应该在函数体内关闭,否则就只能等gc了。statement这种对象比较消耗资源,能避免gc尽量避免。
21 楼 moshalanye 2008-08-26  
引用
由于项目中其他同学也在用他这个模板,他们觉得很方便。但对应新人(刚毕业的同学)来说,经常在调试的时候发生了错误,都不知错误发生在那?导致又要其他同学帮忙,乱费太多时间,而且他们还是不知其所以然。


      楼主:如果你是用的sql Server 数据库   同时还是用微软的那个数据库驱动,好像是有蛮多bug的,最离谱的一个bug 就是不能重复读 resultSet的数据,所以只要debug 取一次数据,运行程序再来一次,就出异常,同时还有长字段不可为空,在有长字段时要按顺序取数据的异常    换成sourceforg 的jdbc驱动就好了
      的确还是感觉springJdbcTemplete 好些,给新人用,又可以学jdbc的使用,又可以很好理解模板和策略,代码也优雅些
20 楼 seemoon 2008-08-26  
做这么个东西跟spring jdbctemplate有什么地方不同?希望能讨论一下
19 楼 土匪一份子 2008-08-26  
楼主测试过性能没问题? 
试下来个50万数据+表中有一个大字段,
应该会有影响吧。
18 楼 jackey3316 2008-08-25  
jacklondon 写道
用 Apache common DBUtils 吧。
它可以直接把 ResultSet 通过反射变成 JavaBean List,比你这里的代码要更高明。
或者用 VelocityWeb, 是在 DBUtils 之上的进一步封装。
顺便说一下,List 的遍历,不管是 LinkedList 还是 ArrayList, 建议都用 Iterator, 不要用 params.get(i).
建议看看 Thinking in Java. 虽然很多人不屑,但是这本书对于 Java Collection 一节,介绍得比其他书都要好。



看完这段代码   我第一想起来的也是dbutil
17 楼 qhfrose 2008-08-25  
感觉太耗内存了。每个Map都字段名和数据对应,如果数据量大,内存浪费还是比较严重的。
16 楼 siriuscor 2008-08-25  
不对sql语句进行分析啊?如果我只取几个字段就出错了.

可以对metadata做一个缓存

相关推荐

    电子商务之价格优化算法:梯度下降:机器学习在价格优化中的角色.docx

    电子商务之价格优化算法:梯度下降:机器学习在价格优化中的角色.docx

    ToadforOracle与Oracle数据库版本兼容性教程.docx

    ToadforOracle与Oracle数据库版本兼容性教程.docx

    browser360-cn-stable-13.3.1016.4-1-amd64.deb

    360浏览器银河麒麟版 for X86 适配兆芯 / 海光 / intel / AMD CPU

    基于React.js和Material-UI个人作品集网站模板(附源码+说明文档).zip

    使用React.js构建,提供多种主题可供选择,并且易于定制。该项目旨在帮助开发者和自由职业者创建自己的个性化投资组合。 主要功能点 多种主题可供选择,包括绿色、黑白、蓝色、红色、橙色、紫色、粉色和黄色 易于定制,可以在src/data文件夹中更新个人信息 包含主页、关于、简历、教育、技能、经验、项目、成就、服务、推荐信、博客和联系等多个部分 支持通过Google表单收集联系信息 提供SEO优化建议 支持多种部署方式,如Netlify、Firebase、Heroku和GitHub Pages 技术栈主要 React.js Material-UI Axios React-fast-marquee React-helmet React-icons React-reveal React-router-dom React-router-hash-link React-slick Slick-carousel Validator

    中小型企业财务管理系统 SSM毕业设计 附带论文.zip

    中小型企业财务管理系统 SSM毕业设计 附带论文 启动教程:https://www.bilibili.com/video/BV1GK1iYyE2B

    apsw-3.38.5.post1-cp39-cp39-win_amd64.whl.rar

    python whl离线安装包 pip安装失败可以尝试使用whl离线安装包安装 第一步 下载whl文件,注意需要与python版本配套 python版本号、32位64位、arm或amd64均有区别 第二步 使用pip install XXXXX.whl 命令安装,如果whl路径不在cmd窗口当前目录下,需要带上路径 WHL文件是以Wheel格式保存的Python安装包, Wheel是Python发行版的标准内置包格式。 在本质上是一个压缩包,WHL文件中包含了Python安装的py文件和元数据,以及经过编译的pyd文件, 这样就使得它可以在不具备编译环境的条件下,安装适合自己python版本的库文件。 如果要查看WHL文件的内容,可以把.whl后缀名改成.zip,使用解压软件(如WinRAR、WinZIP)解压打开即可查看。 为什么会用到whl文件来安装python库文件呢? 在python的使用过程中,我们免不了要经常通过pip来安装自己所需要的包, 大部分的包基本都能正常安装,但是总会遇到有那么一些包因为各种各样的问题导致安装不了的。 这时我们就可以通过尝试去Python安装包大全中(whl包下载)下载whl包来安装解决问题。

    电子商务之价格优化算法:线性回归:价格优化策略实施.docx

    电子商务之价格优化算法:线性回归:价格优化策略实施.docx

    工业数字化转型的关键技术及其应用场景解析

    内容概要:报告详细介绍了企业数字化转型的驱动因素、数字化转型方案分类及其应用场景,重点关注了云计算、超连接、数字孪生、人工智能、分布式账本、增材制造、人机接口、数据共享、工业物联网等关键技术。这些技术不仅支持了企业的运营效率提升和业务模式创新,也为实现更快、更开放、更高效的数字化转型提供了支撑。报告最后提出了企业实施数字化转型的六个步骤。 适合人群:企业高级管理人员、技术人员、咨询顾问,以及对工业数字化转型感兴趣的读者。 使用场景及目标:帮助企业制定和实施数字化转型策略,优化运营模式,提升业务效率,增强市场竞争力。同时,也可作为政府部门、研究机构和行业协会的参考文献。 其他说明:报告中提到的关键技术及其应用场景对企业数字化转型具有重要的指导意义,特别是对于那些希望通过数字化转型实现业务创新和升级的企业。

    基于java的线上选课系统的设计与实现答辩PPT.pptx

    基于java的线上选课系统的设计与实现答辩PPT.pptx

    原版aggdraw-1.3.15-cp311-cp311-win_arm64.whl-下载即用直接pip安装.zip

    安装前的准备 1、安装Python:确保你的计算机上已经安装了Python。你可以在命令行中输入python --version或python3 --version来检查是否已安装以及安装的版本。 个人建议:在anaconda中自建不同python版本的环境,方法如下(其他版本照葫芦画瓢): 比如创建python3.8环境,anaconda命令终端输入:conda create -n py38 python==3.8 2、安装pip:pip是Python的包管理工具,用于安装和管理Python包。你可以通过输入pip --version或pip3 --version来检查pip是否已安装。 安装WHL安装包 1、打开命令行(或打开anaconda命令行终端): 在Windows上,你可以搜索“cmd”或“命令提示符”并打开它。 在macOS或Linux上,你可以打开“终端”。 2、cd到whl文件所在目录安装: 使用cd命令导航到你下载的whl文件所在的文件夹。 终端输入:pip install xxx.whl安装即可(xxx.whl指的是csdn下载解压出来的whl) 3、等待安装完成: 命令行会显示安装进度,并在安装完成后返回提示符。 以上是简单安装介绍,小白也能会,简单好用,从此再也不怕下载安装超时问题。 使用过程遇到问题可以私信,我可以帮你解决! 收起

    电子商务之价格优化算法:贝叶斯定价:贝叶斯网络在电子商务定价中的应用.docx

    电子商务之价格优化算法:贝叶斯定价:贝叶斯网络在电子商务定价中的应用.docx

    IMG_20241105_235746.jpg

    IMG_20241105_235746.jpg

    基于java的毕业设计选题系统答辩PPT.pptx

    基于java的毕业设计选题系统答辩PPT.pptx

    专升本考试资料全套.7z

    专升本考试资料全套.7z

    Trustwave DbProtect:数据库活动监控策略制定.docx

    Trustwave DbProtect:数据库活动监控策略制定.docx

    VB程序实例-CD-ROM开关.zip

    基于VB的程序实例,可供参考学习使用

    课设毕设基于SpringBoot+Vue的教育资源共享平台源码可运行.zip

    本压缩包资源说明,你现在往下拉可以看到压缩包内容目录 我是批量上传的基于SpringBoot+Vue的项目,所以描述都一样;有源码有数据库脚本,系统都是测试过可运行的,看文件名即可区分项目~ |Java|SpringBoot|Vue|前后端分离| 开发语言:Java 框架:SpringBoot,Vue JDK版本:JDK1.8 数据库:MySQL 5.7+(推荐5.7,8.0也可以) 数据库工具:Navicat 开发软件: idea/eclipse(推荐idea) Maven包:Maven3.3.9+ 系统环境:Windows/Mac

    基于Thinkphp5框架的Java插件设计源码

    该源码项目是一款基于Thinkphp5框架的Java插件设计,包含114个文件,其中Java源文件60个,PNG图片32个,XML配置文件7个,GIF图片7个,Git忽略文件1个,LICENSE文件1个,Markdown文件1个,Xmind文件1个,Idea项目文件1个,以及JAR文件1个。

    数据库开发和管理最佳实践.pdf

    数据库开发和管理最佳实践.pdf

    课设毕设基于SpringBoot+Vue的农场投入品运营线上管理系统源码可运行.zip

    本压缩包资源说明,你现在往下拉可以看到压缩包内容目录 我是批量上传的基于SpringBoot+Vue的项目,所以描述都一样;有源码有数据库脚本,系统都是测试过可运行的,看文件名即可区分项目~ |Java|SpringBoot|Vue|前后端分离| 开发语言:Java 框架:SpringBoot,Vue JDK版本:JDK1.8 数据库:MySQL 5.7+(推荐5.7,8.0也可以) 数据库工具:Navicat 开发软件: idea/eclipse(推荐idea) Maven包:Maven3.3.9+ 系统环境:Windows/Mac

Global site tag (gtag.js) - Google Analytics