JDBC性能优化
一、使用PreparedStatement的Batch功能
参见本人一下文章:http://blog.csdn.net/lmb55/article/details/50631062
二、选择合适的光标类型
选择合适的光标类型以最大限度的适用你的应用程序。(以下列出三种光标类型的性能问题)
对于从一个表中顺序读取所有记录的情况来说, Forward-Only型的光标提供了最好的性能。 获取表中的数据时, 没有哪种方法比使用Forward-Only型的光标更快。 但不管怎样, 当程序中必须按无次序的方式处理数据行时, 这种光标就无法使用了。
对于程序中要求与数据库的数据同步以及要能够在结果集中前后移动光标, 使用JDBC的Scroll-Insensitive型光标是较理想的选择。 此类型的光标在第一次请求时就获取了所有的数据(当JDBC驱动采用’lazy’方式获取数据时或许是很多的而不是全部的数据)并且储存在客户端。 因此, 第一次请求会非常慢,特别是请求长数据时会理严重。而接下来的请求并不会造成任何网络往返(当使用’lazy’方法时或许只是有限的网络交通) 并且处理起来很快。因为第一次请求速度很慢,Scroll-Insensitive型光标不应该被使用在单行数据的获取上。 当有要返回长数据时,开发者也应避免使用Scroll-Insensitive型光标, 因为这样可能会造成内存耗尽。 有些Scroll-Insensitive型光标的实现方式是在数据库的临时表中缓存数据来避免性能问题,但多数还是将数据缓存在应用程序中。
Scroll-Sensitive型光标,有时也称为Keyset-Driven光标,使用标识符,像数据库的ROWID之类。当每次在结果集移动光标时, 会重新该标识符的数据。 因为每次请求都会有网络往返, 性能可能会很慢。无论怎样,用无序方式的返回结果行对性能的改善是没有帮助的。
现在来解释一下这个, 来看这种情况。一个程序要正常的返回1000行数据到程序中. 在执行时或者第一行被请求时, JDBC驱动不会执行程序提供的SELECT语句. 相反, 它会用键标识符来替换SELECT查询, 例如, ROWID. 然后修改过的查询都会被驱动程序执行,跟着会从数据库获取所有1000个键值. 每一次对一行结果的请求都会使JDBC驱动直接从本地缓存中找到相应的键值, 然后构造一个包含了’WHERE ROWID=?’子句的最佳化查询, 再接着执行这个修改过的查询, 最后从服务器取得该数据行。
当程序无法像Scroll-Insensitive型光标一样提供足够缓存时, Scroll-Sensitive型光标可以被替代用来作为动态的可滚动的光标。
三、使用有效的getter方法
JDBC提供多种方法从ResultSet中取得数据,像getInt(), getString(), 和getObject()等等。 而getObject()方法是最泛化了的, 提供了最差的性能。 这是因为JDBC驱动必须对要取得的值的类型作额外的处理以映射为特定的对象。 所以就对特定的数据类型使用相应的方法.
要更进一步的改善性能, 应在取得数据时提供字段的索引号, 例如, getString(1), getLong(2), 和getInt(3)等来替代字段名。 如果没有指定字段索引号。网络交通不会受影响。 但会使转换和查找的成本增加。例如,假设你使用getString(“foo”) … JDBC驱动可能会将字段名转为大写(如果需要),并且在到字段名列表中逐个比较来找到”foo”字段。 如果可以,直接使用字段索引,将为你节省大量的处理时间。
例如,假设你有一个100行15列的ResultSet,字段名不包含在其中。你感兴趣的是三个字段 EMPLOYEENAME (字串型), EMPLOYEENUMBER (长整型), 和SALARY (整型)。 如果你指定getString(“EmployeeName”), getLong(“EmployeeNumber”), 和getInt(“Salary”), 查询旱每个字段名必须被转换为metadata中相对应的大小写,然后才进行查找。如果你使用getString(1), getLong(2), 和getInt(15)。 性能就会有显著改善。
四、选择合适的数据类型
接收和发送某些数据可能代价昂贵。当你设计一个schema时, 应选择能被最有效地处理的数据类型。 例如, 整型数就比浮点数或实数处理起来要快一些。浮点数的定义是按照数据库的内部规定的格式,通常是一种压缩格式。 数据必须被解压和转换到另外种格式,这样它才能被数据的协议处理。
五、获取ResultSet
由于数据库系统对可滚动光标的支持有限, 许多JDBC驱动程序并没有实现可滚动光标。除非你确信数据库支持可滚动光标的结果集,否则不要调用rs.last()和rs.getRow()方法去找出数据集的最大行数。因为JDBC驱动程序模拟了可滚动光标, 调用rs.last()导致了驱动程序透过网络移到了数据集的最后一行。取而代之,你可以用ResultSet遍历一次计数或者用SELECT查询的COUNT函数来得到数据行数。
通常情况下,不要写那种依赖于结果集行数的代码, 因为驱动程序必须获取所有的数据集以便知道查询会返回多少行数据,当表中的数据量非常大时,这种做法是非常消耗性能的。
六、获取自动生成的键值
当插入一条记录时,我们很多时候都想马当前插入的主键返回出来.
如果主键是自动生成的(大多数时候是这样),那么取回主键是一种比较困难的事.
可能对于一些特殊的数据库必须把insert into和select max(key)或什么序列当前值作为一个事务的原子来操作,但很多数据库(以及数据库操作环境)并不能为你提供事务并发控制.所以如果多人同时操作,那么select max(key)很可能就不是你刚才insert的那条记录.
在SQL server 很方便,有现程的sql可以用
INSERT INTO tableName (fieldList ...) values (valueList ...) SELECT @@IDENTITY AS aliasName;
- 1
该SQL的示例如下:
--创建表
create table OrgInfo
(
OrgId int identity(1,1) primary key,
OrgName nvarchar(20)
)
--插入测试数据
insert into OrgInfo
select '张三' union select '李四' union select '王五'
select * from OrgInfo
/*
OrgId OrgName
----------- --------------------
1 李四
2 王五
3 张三
*/
--假设此时我们再插入一条,然后得到新插入的id
insert into OrgInfo select '刘六'
--得到新插入的id
select @@identity
/*
4
*/
--得到新插入的数据行
select * from OrgInfo where OrgId=@@identity
/*
OrgId OrgName
----------- --------------------
4 刘六
*/
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
在Oracle中,有两种方案:
1、使用JDBC的getGeneratedKeys()方法,第一次返回oracle的rowid,第二次使用返回的rowid查询该条数据。
String sql = "insert into xx_cust(cust_type,cust_name,login_name)"
+ " values('ipn','aaa','bb')";
//省略创建数据库连接的过程
PreparedStatement stmt = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
stmt.execute();
ResultSet rs = stmt.getGeneratedKeys();
rs.next();
String rowid=rs.getString(1);
System.out.println("rowid="+rowid);//返回rowid
PreparedStatement preparedStatement =conn.prepareStatement("select cust_id from xx_cust where rowid=?");
preparedStatement .setString(1, rowid);
ResultSet rs2 = preparedStatement.executeQuery();
rs2.next();
String custId=rs2.getString(1);
System.out.println("custid="+custId);//通过rowid查询插入的数据
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
2、使用oracle的returning语句
String sql = "insert into xx_cust(cust_type,cust_name,login_name)"
+ " values('ipn','aaa','bb') returning cust_id into ?";
OraclePreparedStatement stmt = (OraclePreparedStatement) conn.prepareStatement(sql);
stmt.registerReturnParameter(1, OracleTypes.INTEGER);
int count = stmt.executeUpdate();
if (count > 0) {
ResultSet rs = stmt.getReturnResultSet();
while (rs.next()) {
String name = rs.getString(1);
System.out.println("name=" + name);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
未完待续。。。
JDBC性能优化的更多相关文章
- JDBC性能优化方案
最近用到了利用JDBC查询Oracle数据库.可是查询效率不尽人意.研究了一下JDBC方面能够优化的地方,在这里跟大家分享一下. 1.设置最优的预取值 defaultRowP ...
- JDBC性能优化篇
系统性能. 少用Metadata方法 与其它的JDBC方法相比, 由ResultSet对象生成的metadata对象的相对来说是很慢的. 应用程序应该缓存从ResultSet返回的metada ...
- mysql jdbc性能优化之mybatis/callablestatement调用存储过程mysql jdbc产生不必要的元数据查询(已解决,cpu负载减少20%)
INFO | jvm 1 | 2016/08/25 15:17:01 | 16-08-25 15:17:01 DEBUG pool-1-thread-371dao.ITaskDao.callProce ...
- JDBC性能优化点
1). 指定数据库连接池中初始化连接数的个数
- JDBC性能分析与优化
JDBC性能分析与优化V1.0http://www.docin.com/p-758600080.html
- 数据库访问性能优化 Oracle
特别说明: 1. 本文只是面对数据库应用开发的程序员,不适合专业DBA,DBA在数据库性能优化方面需要了解更多的知识: 2. 本文许多示例及概念是基于Oracle数据库描述,对于其它关系型数据库也 ...
- SQL性能优化常见措施(Lock wait timeout exceeded)
SQL性能优化常见措施 目 录 1.mysql中explain命令使用 2.mysql中mysqldumpslow的使用 3.mysql中修改my.ini配置文件记录日志 4.mysql中如何加索引 ...
- Hibernate的性能优化问题
本文是根据Hibernate帮助文档,以及一些书籍及项目经验整理而成,只提供要点和思路,具体做法可以留言探讨,或是找一些更详细更有针对性的资料. 初用Hibernate的人也许都遇到过性能问题,实现同 ...
- JVM内存模型和性能优化 转
JVM内存模型和性能优化 JVM内存模型优点 内置基于内存的并发模型: 多线程机制 同步锁Synchronization 大量线程安全型库包支持 基于内存的并发机制,粒度灵活控制,灵活度高于 ...
随机推荐
- 离线安装Cloudera Manager5.3.4与CDH5.3.4
文章转载:http://www.aboutyun.com/thread-14024-1-1.html 前期准备工作(系统环境搭建) 操作系统:CentOS 6.5 x64 CPU*2 64G 300G ...
- javaWeb_使用标签库简化jsp
jsp标签库.也叫自己定义标签. 应用范围 jsp标签.主要应用于前台页面.在jsp中.假设jsp中存在<% %> 等 java代码.那么对前台开发者来说.就须要了解 java代码. 怎样 ...
- vs2013生成lib
引擎cocos2d-x-3.1.1 一. cocos创建一个项目.随便是lua还是cpp.这里用cpp演示 二.创建完毕之后执行下项目 之后创建两个类.例如以下 TestLib.cpp文件 #incl ...
- .NET Core/.NET之Stream简介 Rx.NET 简介
.NET Core/.NET之Stream简介 之前写了一篇C#装饰模式的文章提到了.NET Core的Stream, 所以这里尽量把Stream介绍全点. (都是书上的内容) .NET Core ...
- VBS 操作Word
VBS 操作Word 1.新建Word文档 '使用Add方法 Dim ObjWD,ObjDOC Set ObjWD=CreateObject("Word.application" ...
- Cocos2d-x项目创建
以创建HelloWorld项目为例子,执行create_project.py脚本,进入Doc界面输入下面的命令: (1)E: (切换盘符,因为我的Cocos2d-x源码在E盘,create_pro ...
- 【PA 2014】Kuglarz
[题目链接] 点击打开链接 [算法] sum[i]表示前i个杯子中,杯子底下藏有球的杯子总数 那么,知道[i,j]这段区间中,藏有球的 ...
- [POI2011]LIZ-Lollipop
https://www.zybuluo.com/ysner/note/1303462 题面 给一个只有\(1\)和\(2\)的序列,每次询问有没有一个子串的和为\(x\). \(n\leq10^6\) ...
- UVA 10559 Blocks —— 区间DP
题目:https://www.luogu.org/problemnew/show/UVA10559 区间DP,有点难想: 为了方便,先把原来就是连续一段相同颜色的点看做一个点,记一下长度: f[i][ ...
- oracle 统计/分析函数
Oracle从8.1.6开始提供分析函数,分析函数用于计算基于组的某种聚合值,它和聚合函数的不同之处是对于每个组返回多行,而聚合函数对于每个组只返回一行. 语法: Sql代码 <analytic ...