- 浏览: 249660 次
- 性别:
- 来自: 南京
文章分类
最新评论
-
lixia0417:
如果代理是使用命令行选项启动的,那么代理类还有一个要使用的 a ...
BTrace系列之五:实现原理 -
java_cache:
不错,讲得挺详细,果断收藏
Eclipse Debug不为人知的秘密 -
zhupeijun23:
有点懂了
HttpClient重定向 -
tss0823:
非常好的文章!
BTrace实际案例分析 -
763863446:
好好好,尽量不要用debug.
Eclipse Debug不为人知的秘密
JDBC当中的批处理
在对数据库进行批量操作时,应分析操作的前后相关性,如果属于大批量的操作,而且前续操作的结果不依赖与后继操作,则完全可以使用批处理来操作DB。
使用批处理的优点:
1. 多个SQL语句的执行,共用一个Connection资源。在对数据库操作时,connection资源是很宝贵的,数据库的维护从某种角度来说,就是减少数据库的连接数,减轻对DB的压力。创建一个数据连接要远远比使用数据库连接消耗资源。这也正是数据库连接池存在的意义。
2. 批处理在效率上总是比逐条处理有优势,要处理的数据的记录条数越大,批处理的优势越明显。在处理大批量相同业务逻辑的DB操作可以使用批处理达到简化、高效处理。
3. 在单一时间段,提高应用与DB间的吞吐量,缩短DB响应时间。大部分应用都有DB操作,如果SQL语句操作不当会导致DB长时间处于不可用状态,或是使DB资源占用率升高,从而影响了应用,最终被DB拖垮。缩短DB的响应时间,一来可以提供应用性能,二来减轻DB压力,对维持高系能的应用有极大的帮助。
使用JDBC本身提供的批处理功能很简单,如下例子是根据主键批量更新test_table表。
+ expand sourceview plaincopy to clipboardprint?
public void updateStateBactch(List elms) {
Connection conn = null;
PreparedStatement ps = null;
String sql = "update test_table set state=? where keyid = ?";
conn = DBTools.getConnection();
if(conn == null)
{
log.error("[update][state][error][conn is null]");
return;
}
try {
ps = conn.prepareStatement(sql);
for(int i = 0; i < elms.size(); i++) {
Element elm = (Element) elms.get(i);
if(null == elm || null == elm.getUserId()
|| null == elm.getState()) {
continue;
}
ps.setInt(1, elm.getStatus());
ps.setString(2, elm.getProcID());
ps.addBatch();
}
ps.executeBatch();
ps.clearBatch();
} catch (SQLException sqlEx) {
log.warn("[update][state][error][SQLException]");
} catch (Exception e) {
log.warn("[update][state][error][SQLException]");
} finally {
DBTools.close(conn, ps, null);
}
}
public void updateStateBactch(List elms) {
Connection conn = null;
PreparedStatement ps = null;
String sql = "update test_table set state=? where keyid = ?";
conn = DBTools.getConnection();
if(conn == null)
{
log.error("[update][state][error][conn is null]");
return;
}
try {
ps = conn.prepareStatement(sql);
for(int i = 0; i < elms.size(); i++) {
Element elm = (Element) elms.get(i);
if(null == elm || null == elm.getUserId()
|| null == elm.getState()) {
continue;
}
ps.setInt(1, elm.getStatus());
ps.setString(2, elm.getProcID());
ps.addBatch();
}
ps.executeBatch();
ps.clearBatch();
} catch (SQLException sqlEx) {
log.warn("[update][state][error][SQLException]");
} catch (Exception e) {
log.warn("[update][state][error][SQLException]");
} finally {
DBTools.close(conn, ps, null);
}
}
使用批处理是有绝对的好处,可是凡事都利必有弊。在使用批处理应用注意以下几点,这些小的细节常常被我们忽略,但是这些细节都对你应用的性能有着至关重要的影响。
1. 使用批出量没有进行分批分量处理。在使用批处理首先应该注意一点,批处理也不是万能的,批处理都存在一次执行的最大吞吐量限制。正如上面所提到的,批处理在单一时间段提高了与DB间的吞吐量,但是任何DB都是有吞吐量最大限制。当达到或是超过,最大吞吐量的峰值时,容易导致DB过载,更严重会导致DB宕机。例如上面的示例代码,如果入参list长度很大,几万甚至几十万,想想会导致上面结果呢。当然是背道而驰使应用的系能急剧下降,而且给DB带来风险。正确的做法应该是分批分量进行提交。处理执行SQL的时候,批处理的分批的大小与数据库的吞吐量以及硬件配置有很大关系,需要通过测试找到最佳的分批大小,一般在200-2000之间。
+ expand sourceview plaincopy to clipboardprint?
try {
ps = conn.prepareStatement(sql);
for(int i = 0; i < elms.size(); i++) {
Element elm = (Element) elms.get(i);
if(null == elm || null == elm.getUserId()
|| null == elm.getState()) {
continue;
}
ps.setInt(1, elm.getStatus());
ps.setString(2, elm.getProcID());
ps.addBatch();
if ((i != 0 && i % 2000 == 0) || i == elms.size() - 1) {
ps.executeBatch();
ps.clearBatch();
ps.close();
ps = conn.prepareStatement(sql);
}
}
} catch (SQLException sqlEx) {
log.warn("[update][state][error][SQLException]");
log.warn(sqlEx);
} catch (Exception e) {
log.warn("[update][state][error][SQLException]");
log.warn(e);
} finally {
DBTools.close(conn, ps, null);
}
try {
ps = conn.prepareStatement(sql);
for(int i = 0; i < elms.size(); i++) {
Element elm = (Element) elms.get(i);
if(null == elm || null == elm.getUserId()
|| null == elm.getState()) {
continue;
}
ps.setInt(1, elm.getStatus());
ps.setString(2, elm.getProcID());
ps.addBatch();
if ((i != 0 && i % 2000 == 0) || i == elms.size() - 1) {
ps.executeBatch();
ps.clearBatch();
ps.close();
ps = conn.prepareStatement(sql);
}
}
} catch (SQLException sqlEx) {
log.warn("[update][state][error][SQLException]");
log.warn(sqlEx);
} catch (Exception e) {
log.warn("[update][state][error][SQLException]");
log.warn(e);
} finally {
DBTools.close(conn, ps, null);
}
2. 使用批处理时,没有关注DB测异常情况,导致批处理失败。这里涉及到一些异常处理最基本的点。上述例程还有个小小的问题需要注意,当ps.executeBatch()执行时,如果该批次的SQL语句中有一条SQL抛出异常,那么后续的批处理将不会有执行的机会,导致漏执行。所以经过优化后:
+ expand sourceview plaincopy to clipboardprint?
try {
ps = conn.prepareStatement(sql);
for(int i = 0; i < elms.size(); i++) {
try {
Element elm = (Element) elms.get(i);
if(null == elm || null == elm.getUserId()
|| null == elm.getState()) {
continue;
}
ps.setInt(1, elm.getStatus());
ps.setString(2, elm.getProcID());
ps.addBatch();
if ((i != 0 && i % 2000 == 0) || i == elms.size() - 1) {
ps.executeBatch();
ps.clearBatch();
ps.close();
ps = conn.prepareStatement(sql);
}
} catch (SQLException e) {
log.warn("[update][state][error][SQLException]");
log.warn(e);
ps.clearBatch();
ps.close();
ps = conn.prepareStatement(sql);
} catch (Exception e) {
log.warn("[update][state][error][SQLException]");
log.warn(e);
ps.executeBatch();
ps.clearBatch();
ps.close();
ps = conn.prepareStatement(sql);
}
}
} catch (SQLException sqlEx) {
log.warn("[update][state][error][SQLException]");
log.warn(sqlEx);
} catch (Exception e) {
log.warn("[update][state][error][SQLException]");
log.warn(e);
} finally {
DBTools.close(conn, ps, null);
}
try {
ps = conn.prepareStatement(sql);
for(int i = 0; i < elms.size(); i++) {
try {
Element elm = (Element) elms.get(i);
if(null == elm || null == elm.getUserId()
|| null == elm.getState()) {
continue;
}
ps.setInt(1, elm.getStatus());
ps.setString(2, elm.getProcID());
ps.addBatch();
if ((i != 0 && i % 2000 == 0) || i == elms.size() - 1) {
ps.executeBatch();
ps.clearBatch();
ps.close();
ps = conn.prepareStatement(sql);
}
} catch (SQLException e) {
log.warn("[update][state][error][SQLException]");
log.warn(e);
ps.clearBatch();
ps.close();
ps = conn.prepareStatement(sql);
} catch (Exception e) {
log.warn("[update][state][error][SQLException]");
log.warn(e);
ps.executeBatch();
ps.clearBatch();
ps.close();
ps = conn.prepareStatement(sql);
}
}
} catch (SQLException sqlEx) {
log.warn("[update][state][error][SQLException]");
log.warn(sqlEx);
} catch (Exception e) {
log.warn("[update][state][error][SQLException]");
log.warn(e);
} finally {
DBTools.close(conn, ps, null);
}
3. 使用批处理时,当批处理中有一条SQL语句优化SQL异常而导致整个批处理失败。在打印日志时应该注意,以上的打印方式对问题定位没有任何帮助。如上如果其中的一条SQL语句执行失败,那么你不知道究竟是什么异常,因为没有打印异常列,而只打印了最顶层异常。例如:如上程序在DB2数据库中执行失败后,只返回了如下信息com.ibm.db2.jcc.c.vd: Non-atomic batch failure. The batch was submitted, but at least one exception occurred on an individual member of the batch. Use getNextException() to retrieve the exceptions for specific batched elements.大概意思是批处理执行失败,批处理已经提交,但是其中至少有一条或者多条执行失败。使用getNextException来查看执行白失败的SQL语句异常信息,便于定位!可是这样还是有问题,你知道了SQL语句的异常了,但是你不知道究竟是那条SQL语句导致的异常,其实可以更具批处理执行的返回值来检查执行结果。
Int[] results = ps.executeBatch();
发表评论
-
BTrace实际案例分析
2012-02-17 17:24 6281BTrace实际案例分析 问题表象 问题描述 ... -
BTrace工具实例应用
2012-02-17 17:18 3904BTrace工具使用简介 “Hello World” ... -
BTrace工具简介
2012-02-17 17:09 12412BTrace工具简介 What is Btrace? ... -
使用JDI调试多线程程序
2012-02-09 11:17 0前几天写了一篇Eclipse的debug技巧,引来不少童鞋的口 ... -
Eclipse Debug不为人知的秘密
2012-02-07 15:54 39001Debug视图 认识debug视图,红色部分框为线程堆栈视 ... -
PIM系统架构浅析
2010-06-20 15:43 2157PIM系统架构浅析 我们真的需要分 ... -
日志打印
2010-06-20 15:26 1709日志打印 ü 日志重要性 ü ... -
JSON简介
2010-06-20 15:22 2443JSON简介 ü JSON简介及其应用场景 ... -
Java编程中汉字问题的初探
2010-06-20 15:09 12031. 前言 在基于Java语言 ... -
接口模块的定义
2010-06-20 14:35 1153接口模块的定义 1 作为接口模块,必须要在设计时仔细逐 ... -
大批量工具的思考
2010-06-20 14:32 875大批量工具的思考 大批量工具的思考:大批量处理工具,适用于数 ... -
Unicode、GBK、UTF-8、ASCII的编码简介
2010-06-20 14:30 3432Unicode、GBK、UTF-8、ASCII的编码简介 ... -
java中乱码问题解决方法
2010-02-04 13:01 1570通过TCP码流识别编码 前几天和北京的MM在联调时候出现一个 ... -
java中的编码简介
2010-01-16 16:48 1352Unicode、GBK、UTF-8、ASCII的编码简介 ... -
大批量工具的思考
2010-01-15 19:51 958大批量工具的思考 大批量工具的思考:大批量处理工具,适用于数 ... -
java当中的批处理
2010-01-15 19:44 10667在对数据库进行批量操作时,应分析操作的前后相关性,如果属于大批 ... -
接口模块的定义
2010-01-15 19:34 12101 作为接口模块,必须要在设计时仔细逐一分析消息的类型。包括: ...
相关推荐
JDBC的批处理操作三种方式JDBC的批处理操作三种方式JDBC的批处理操作三种方式JDBC的批处理操作三种方式JDBC的批处理操作三种方式
讲述java中JDBC的批处理功能,讲述java中JDBC的批处理功能,讲述java中JDBC的批处理功能
JDBC进行批处理共4页.pdf.zip
JDBC基本操作,及批处理操作
NULL 博文链接:https://157538651.iteye.com/blog/1689291
用pinyin4j获取拼音简码JXL读写Excl文件JDBC批处理
内容为JDBC增删改查 ,事物处理, 批处理,以及预编译示例代码
NULL 博文链接:https://j2ee2009.iteye.com/blog/660826
对jdbc的操作进行说明,避免出现大数据读取时的报错
这个压缩包包含了传智播客方立勋老师的JDBC笔记,是比较经典的学习资料。
Java教程中阐述了接口在开发中的真正作用,JDBC规范制定的背景,JDBC编程六部曲,JDBC事务,JDBC批处理,SQL注入,行级锁等,是学习JDBC最好的Java教程。JDBC 资源太大,传百度网盘了,链接在附件中,有需要的同学...
2. JDBC当中的元数据 3. 事务(ACID) 4. 事务边界的划分: 5. 使用事务过程中可能出现的异常情况: 6. 事务的隔离级别 第五章 JDBC2.0 1. ResultSet的可滚动性(默认只能向下(向前)移动) 2. ResultSet的可更新性(默认是...
JDBC进阶2
详细介绍JDBC的连接操作数据库、处理大数据、批处理使用操作 Sun公司为了简化数据库开发,定义了一套JDBC接口,这套接口由数据库厂商去实现,这样,开发人员只需要学习JDBC接口, 并通过JDBC加载具体的驱动,就可以...
JDBC从物理结构上说就是Java语言访问数据库的一套接口集合。从本质上来说就是调用者(程序员)和实现者(数据库厂商)之间的协议。JDBC的实现由数据库厂商以驱动程序的形式提供。JDBC API 使得开发人员可以使用纯...
这是jdbc 批处理输入大量数据到mysql的代码,应该会比较有用
JDBC 的常用API JDBC操作数据库的步骤 JDBC批处理 大数据处理 mybatis3.2数据库框架
本套视频教程中讲解了Java语言如何连接数据库,对数据库中的数据进行增删改查操作,适合...Java教程中阐述了接口在开发中的真正作用,JDBC规范制定的背景,JDBC编程六部曲,JDBC事务,JDBC批处理,SQL注入,行级锁等。
我们可以使用addBatch()和executeBatch()方法选择标准的JDBC批处理,或者通过利用PreparedStatement对象的setExecuteBatch()方法和标准的executeUpdate()方法选择速度更快的Oracle专有的方法。要使用Oracle专有的...
JDBC(powernode CD2206)详尽版 (教学视频、源代码、SQL文件) 包含:教学视频、源代码(与博客同步)、SQL文件 一、介绍 二、JDBC常用的接口和类 2.1 Driver接口 2.2 DriverManager类 2.3 Connection接口 2.4 ...