优化JDBC编程-多提提意见
优化JDBC编程
这是我根据MS SQL SERVER 2000 JDBC DRIVER HELP,并参考其它资料整理而成。ms的这个帮助文件实在有失大家风范,示例代码很.....有兴趣者可以去下载http://download.microsoft.com/download/SQLSVR2000/jdbc/2000/NT45XP/EN-US/setup.exe。由于本人水平有限,文中不当之处请大家批评指正。
1.尽量减少对数据库元数据方法的使用
同样是产生一个ResultSet对象,DatabaseMetaData 对象的方法比其它JDBC方法相对要慢,因此平繁使用该方法会降低系统的性能。在程序中应当对产生的结果集信息进行高速缓存,比如将getTypeInfo()返回的结果集存入Vector或Hashtable中,这样可大大提高程序的效率。
2.应避免的方法调用模式
在方法调用时应当尽量避免传入null做为参数,虽然有时能执行成功,但这对DB Server负担很重。其实在很多情况下所需的参数是已知的。比如:
//这里略去了捕获违例代码(下同)。
DatabaseMetaData md=...;
ResultSet rs=md.getTables(null,null,"authors",null);//取得MS SQL SERVER pubs数据库中authors表的信息.
应当写成:
ResultSet rs=md.getTables("northwind","dbo","authors",new String[]{"TABLE"});
这样使程序更有效可靠。
3.使用哑查询语句来取得表的相关特征信息
一个哑查询语句(Dummy Query,译为哑查询不知是否恰当,愿与大家探讨)不会产生有记录的结果集,比如:select * from tableName where 1=0,因为条件永不成立,DB Server 不会执行这条语句。因此,在不需产生记录行的情况下,哑查询能极大地提高程序的执行效率。比如我们要了解一个表的有关列信息时,上面的语句比select * from tableName这个语句要高效得多,后者数据库服务器要检索所有的行并返回一个记录集,而前者不需要。针对这一问题,JDBC可以有以下两种方法:
case 1:使用getColumns()方法
//getColumns()是DatabaseMetaData的一个方法,其有关信息请查阅JDK1.3文档
ResultSet rs=md.getColumns("pubs","dbo","authors",...);//返回一个有记录的结果集
while(rs.next())//通过滚动结果集取得列名
System.out.println(rs.getString(4));
case 2:使用getMetaData()方法
Statement stmt=conn.createStatement();
//数据库服务器永远不会执行这条查询语句
ResultSet rs=stmt.executeQuery("select * from authors where 1=0");
ResultSetMetaData rsmd=rs.getMetaData();
int colCount=rsmd.getColumnCount();//取得列数
for(int col=1;col<=colCount;col++)
System.out.println(rsmd.getColumnName(col));
//!这里列的顺序是select后列出现的顺序,并不一定与表中列顺序对应
通过以上的分析,第二种方法应是我们的选择。
4.关于存储过程的调用
由于所有的JDBC驱动总是将SQL语句作为字符串发送到数据库服务器,数据库服务器经过语法分析、参数类型验证,然后将参数转换成正确的数据类型再去执行。比如有这么一个存储过程:
CallableStatement cstmt=conn.prepareCall("{call getCustomerName(123)}");
//获得指定id的客户的名字,输入参数,id是个正整数
ResultSet rs=cstmt.executeQuery();
在这里我们认为123是一个正整数,但实际"call getCustomerName(123)"作为字符串整个被发送到数据库服务器端,数据库服务器经过分析,离析出"123"将其转换为整数型值再做为参数送给存储过程执行。很明显,这样效率极低,因为我们把已知的东西仍要服务器去判断,这无疑额外加重了服务器的负担。做为优化也是我们常见的存储过程的调用方法应是:
CallableStatement cstmt=conn.prepareCall("call getCustomerName(?)");
cstmt.setLong(1,123);//将值和类型信息编码后发送
ResultSet rs=cstmt.executeQuery();
//do something
5.正确使用Statement和PreparedStatement对象及其execute方法
Statement 对象是为仅执行一次的查询语句优化而设计的,PreparedStatement 对象是为两次或更多次执行同一查询语句而设计的。PreparedStatement 对象第一次执行一个准备好的查询要花一定的代价,然而它带来的好处是为以后的查询加快了速度;因为SQL语句已经进行编译并放入高速缓存,你可以一直重复使用;想要改变查询条件获得不同的结果集只需用setXXX方法改变主机变量(?)的值就行了。
由于PreparedStatement 及 CallableStatement都是Statement的子类,所以它们都有execute(String sql),executeQuery(String sql),executeUpdate(String sql),executeBatch()方法。
execute(String sql)方法返回一个boolean值,它执行任意复杂的sql语句,可以产生多个结果集。如果有结果产生返回 true,如果没有结果集产生或仅是一个更新记数则返回 false。它产生的结果集可以通过getResultSet()和getMoreResults()获得,更新记数可通过getUpdateCount()获得。显然execute(String sql)方法的使用要复杂一些,因此如果只是简单的查询或更新操作请使用executeQuery(String sql)和executeUpdate(String sql)方法。executeUpdate(String sql)能执行INSERT,UPDATE,DELETE语句,及DDL和DML命令(此时返回值为0)。
如果需要进行更多的更新操作,只需将这些更新命令打包后一起提交给数据库,数据库一次处理所有的请求,这比逐条提交要高效得多。例如:
//保存当前提交模式
boolean commitState=conn.getAutoCommit();
// 关闭自动提交模式
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
//逐条加入
stmt.addBatch("INSERT INTO employees VALUES (1000, 'Joe Jones')");
stmt.addBatch("INSERT INTO departments VALUES (260, 'Shoe')");
stmt.addBatch("INSERT INTO emp_dept VALUES (1000, 260)");
// 一次提交
int[] updateCounts = stmt.executeBatch();
conn.commit();//使更新生效
conn.setAutoCommit(commitState);//恢复原来的提交模式
PreparedStatement和CallalbeStatement对象的使用基本与Statement一样,请参阅JDBC2.1API。
6.正确的使用游标
JDBC2.1核心API提供三种结果集类型:forward-only, scroll-insensitive和scroll-sensitive。
forward-only:仅向前型。如果你仅需要前向顺序滚动结果集中的所有行,仅向前游标能提供极高的性能;然而它不能从第一行上直接滚动到最后一行,也不能从最后一行滚到第一行。
scroll-insensitive:滚动不敏感型。对于要求较高处理级别的应用来说,滚动不敏感型结果集是一个理想的选择,它支持向前和向后的记录集滚动。滚动不敏感型结果集的第一次请求是从数据库服务端取得所有满足条件的行,然后将它存储在客户端,也就是说是一个包含数据的客户端静态视图;虽然以后的操作比较快,但数据库服务器处理第一次的请求非常慢,尤其是当返回的数据量比较大时。因此,如果返回的只是一行记录我们就不应使用这种游标,使用仅向前就满足要求了;相反,如果返回的记录非常多,也不推荐使用这种游标,因为这些数据都存放在内存里,大量的数据将很快使内存耗尽。有些滚动不敏感游标的实现是将数据缓存到数据库服务器的一个临时表中,以免占用过多的内存资源。
scroll-sensitive:滚动敏感型,有时也叫键集驱动游标。它是在你的数据库上对满足条件的记录行做了一个标识,好像行的主键,当你滚动结果集的时候,只有有标识的数据才会返回。由于每次的请求都要产生一次网络连接,因此速度是很慢的。
7.只返回需要的行或列
听了上周六范生对Oracle核心的剖析,我算是搞清楚了对表的查询或更新,数据库低层操作其实是对磁盘文件的read or write,而I/O操作数据量越大耗时越多,软盘的读写速度大家是有目共睹的。为了避免不必要的数据传输,请小心使用select * from ...这样的语句,如果只需要一列就没必要返回所有的列,特别是当你不需要的列中含有大数据类型(如BINARY,BLOB,CLOB)或者说数据量较大时,会影响系统性能。
8.使用连接池
连接池对数据库访问性能的提高是非常显著地,因为创建和销毁一个连接的代价都非常昂贵。连接池实现了数据库连接的共享,一个连接对象可以被多个用户多次重复使用。由容器管理的连接池就像是一个租赁公司,谁要使用就租给他一个,用完后还给我,下次要用接着出租,这样就免去了每次请求都要造个新的,而用完后又把它扔了。
关于连接池技术较为复杂,不过你也完全可以写自己的连接池对象,如果你看了《JAVA2高级编程》。
[参考资料]
1.MS SQL SERVER 2000 JDBC DRIVER HELP
2.《JAVA2高级编程》
3.《JAVA2核心技术II》
4.《J2EE构建企业系统专家级解决方案》
5.《JSP高级编程》
6.SUN JDBC2.1 API
优化JDBC编程-多提提意见的更多相关文章
- JDBC编程之程序优化
-----------------siwuxie095 首先下载 MySQL 的 JDBC 驱动,下载链接: https://dev.mysql.com/downloads/connector/j/ ...
- Spring+SpringMVC+MyBatis+easyUI整合优化篇(九)数据层优化-jdbc连接池简述、druid简介
日常啰嗦 终于回到既定轨道上了,这一篇讲讲数据库连接池的相关知识,线程池以后有机会再结合项目单独写篇文章(自己给自己挖坑,不知道什么时候能填上),从这一篇文章开始到本阶段结束的文章都会围绕数据库和da ...
- JavaEE之JDBC编程[详解]
1.数据库简介 数据库(DB,Data Base ) 数据库管理系统(DBMS,Data Base Management System) 关系型数据库(RDB) 关系型数据库管理系统(RDBMS) S ...
- JDBC编程之预编译SQL与防注入式攻击以及PreparedStatement的使用教程
转载请注明原文地址: http://www.cnblogs.com/ygj0930/p/5876951.html 在JDBC编程中,常用Statement.PreparedStatement 和 ...
- 数据层优化-jdbc连接池简述、druid简介
终于回到既定轨道上了,这一篇讲讲数据库连接池的相关知识,线程池以后有机会再结合项目单独写篇文章(自己给自己挖坑,不知道什么时候能填上),从这一篇文章开始到本阶段结束的文章都会围绕数据库和dao层的优化 ...
- JDBC编程之预编译SQL与防注入
在JDBC编程中,常用Statement.PreparedStatement 和 CallableStatement三种方式来执行查询语句,其中 Statement 用于通用查询, PreparedS ...
- MySQL之JDBC编程增删改查
MySQL之JDBC 一.JDBC是什么 Java DatabaseConnectivity (java语言连接数据库) 二.JDBC的本质 JDBC是SUN公司制定的一套接口(interface). ...
- 单独使用jdbc编程问题总结(一)
在学习Mybatis之前,我们先来回顾JDBC编程的相关知识.在此基础上深入的学习Mybatis框架.如有错误,敬请指正. (一)首先我们既然要使用jdbc,当然是要操作数据库了.创建一个名为:myb ...
- 浅谈JDBC编程
一.概述 1.为什么要用JDBC 数据库是程序不可或缺的一部分,每一个网站和服务器的建设都需要数据库.对于大多数应用程序员(此处不包含数据库开发人员)来说,我们更多的不是在DBMS中对数据库进行操纵, ...
随机推荐
- C++中bool类型变量初值对程序的影响
很困惑的一个问题 #include<iostream> using namespace std; int main() { //bool a=true; //非0(1,2,3,……)输出1 ...
- Linux下Github的使用方法
1 Linux下Git和GitHub环境的搭建 安装Git, 使用命令sudo apt-get install git 创建GitHub帐号 生成ssh key,使用命令 ssh-keygen -t ...
- Scala入门2(特质与叠加在一起的特质)
一.介绍 参考http://luchunli.blog.51cto.com/2368057/1705025 我们知道,如果几个类有某些共通的方法或者字段,那么从它们多重继承时,就会出现麻烦.所以Jav ...
- 1. python 类型和运算
类型和运算 (Types and Operations) Introducing Python Object Types 在非正式的意义上, 在 Python 中, 我们用一些东西做事情. " ...
- NetStandard类库实现Log4Net集成
前面都是Log4Net集成到NetCore项目中,集成到NetStandard类库还是第一次,所以记录一下 小提示:NetStandard要想同时被NetCore和NetFramework调用,需要在 ...
- HTTP/FTP压力测试工具siege
HTTP/FTP压力测试工具siege 压力测试可以检测服务器的承载能力.针对HTTP和FTP服务,Kali Linux提供专项工具siege.该工具可以模拟多个用户同时访问同一个网站的多个网页, ...
- [ 转载 ] Java基础10--关于Object类下所有方法的简单解析
关于Object类下所有方法的简单解析 类Object是类层次结构的根类,是每一个类的父类,所有的对象包括数组,String,Integer等包装类,所以了解Object是很有必要的,话不多说,我们直 ...
- http常见请求头与响应头
1.HTTP常见的请求头 If-Modified-Since:把浏览器端缓存页面的最后修改时间发送到服务器去,服务器会把这个时间与服务器上实际文件的最后修改时间进行对比.如果时间一致,那么返回304, ...
- 【堆优化Dijkstra】BZOJ4152- [AMPPZ2014]The Captain
[题目大意] 给定平面上的n个点,定义(x1,y1)到(x2,y2)的费用为min(|x1-x2|,|y1-y2|),求从1号点走到n号点的最小费用. [思路] 按照某维坐标排序,相邻两个点在这一维度 ...
- ngx_lua配置及应用
一.说明 这里不对lua语言本身及其编译器运行环境等做介绍,以下所有介绍前提对lua相关有所了解. 二.ngx_lua介绍 原理 ngx_lua将Lua嵌入Nginx,可以让Nginx执行Lua脚本, ...