`
mgoann
  • 浏览: 253973 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

JDBC当中的批处理

    博客分类:
  • Java
阅读更多

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();

分享到:
评论

相关推荐

    JDBC的批处理操作三种方式

    JDBC的批处理操作三种方式JDBC的批处理操作三种方式JDBC的批处理操作三种方式JDBC的批处理操作三种方式JDBC的批处理操作三种方式

    使用JDBC的批处理功能

    本文将详细阐述JDBC批处理的基本概念、优势以及如何在实际应用中使用。 一、批处理的概念 批处理是指一次性提交多个SQL语句到数据库进行执行,而不是逐个发送和执行。在JDBC中,批处理主要通过Statement或...

    JDBC进行批处理共4页.pdf.zip

    **JDBC批处理详解** 在Java数据库连接(Java Database Connectivity, JDBC)中,批处理是一项重要的功能,它允许开发者一次性提交多个SQL语句,从而提高数据处理的效率和性能。批处理是数据库操作中的优化手段,...

    JDBC高级批处理

    JDBC批处理的实现依赖于数据库驱动的实现,不同数据库的驱动可能会有不同的优化策略。深入研究JDBC源码,可以帮助我们理解批处理在底层是如何工作的,以及如何针对特定数据库优化性能。 ### 8. 工具支持 很多...

    jdbc 批处理.rar

    在给定的博客链接中,可能详细解释了这些概念,并提供了示例代码来演示如何在实际应用中实现JDBC批处理。通过学习这个资源,开发者可以更好地理解和应用批处理技术,提升Java数据库应用程序的效率。

    JDBC数据库操作值MySQL批处理操作

    MySQL批处理是JDBC提供的一种优化数据库操作的方法,它允许开发者一次提交多个SQL语句,从而提高数据处理效率。本文将深入探讨JDBC在MySQL数据库中的应用,以及如何实现批处理操作。 首先,理解JDBC的基础知识至关...

    JDBC批处理数据

    ### JDBC批处理数据 在Java开发中,JDBC(Java Database Connectivity)是一种广泛使用的数据库连接技术,它允许Java应用程序与各种类型的数据库进行交互。当处理大量数据时,使用JDBC进行有效的数据操作变得尤为...

    用pinyin4j 获取拼音简码 + JXL 读写Excl文件 + JDBC 批处理

    例如,如果你需要更新大量用户的数据,可以使用JDBC批处理来批量更新,减少网络通信和数据库事务处理的开销。 结合这三个技术,我们可以实现一个功能强大的系统。例如,一个基于Web的应用可能需要从用户上传的Excel...

    jdbc 增删改查事物处理, 批处理,以及预编译示例代码

    在Java数据库连接(JDBC)中,增删改查(CRUD)操作是与数据库交互的基础,事务处理、批处理和预编译SQL语句则是提高效率和保证数据一致性的关键技术。以下是对这些概念的详细说明: 1. **JDBC增删改查(CRUD)**:...

    JDBC笔记 方立勋

    方立勋老师的JDBC笔记还会深入到JDBC的高级特性,如JDBC批处理、连接池的使用、JNDI数据源、以及JDBC的最新版本特性等,这些都是Java开发者必须掌握的技能。通过这些笔记的学习,读者将能够熟练地使用JDBC进行数据库...

    Mybatis与JDBC批量插入MySQL数据库性能测试

    2. **事务大小**:在JDBC中,可以通过设置合适的批处理大小来平衡性能和内存消耗。在Mybatis中,批处理的大小由flushStatements()的调用频率决定。 3. **数据库配置**:如InnoDB引擎的缓冲池大小、重做日志大小等,...

    关于hibernate的批处理

    10. **JDBC批处理API**: Hibernate底层使用JDBC的批处理API(Statement.addBatch()和Statement.executeBatch()),用户也可以直接使用JDBC批处理,绕过Hibernate的部分逻辑,获取更高的性能。 11. **性能优化注意...

    jdbc jdbc jdbc

    6. **批处理(Batch Processing)**:对于需要执行大量相似SQL语句的情况,JDBC提供批处理功能,允许一次发送多个SQL语句,从而提高效率。 7. **JDBC URL**:每个数据库驱动都有一个特定的JDBC URL格式,用于标识要...

    JDBC教程

    JDBC批处理 批处理可以提高性能,通过批量执行多条SQL语句。可以使用Statement对象的`addBatch()`方法添加SQL语句到批处理队列,然后通过`executeBatch()`执行。 ### 6. JDBC性能优化 - 使用PreparedStatement...

    JDBCDriver3.0.rar_jdbc driver 3.0_sql jdbc 3.0_sql server jdbc_s

    《深入理解JDBC Driver 3.0:聚焦SQL Server JDBC》 在IT行业中,数据库连接是应用程序与数据存储之间的桥梁,而JDBC(Java Database Connectivity)则是Java平台中用于访问数据库的标准API。JDBC Driver 3.0是针对...

    SQLserver2005最新JDBC驱动

    6. **批处理**:对于大量相似的SQL操作,JDBC支持批处理,可以提高效率。通过`Statement.addBatch()`添加SQL,然后通过`Statement.executeBatch()`一次性执行。 7. **结果集处理**:通过ResultSet对象,开发者可以...

    sqlserver在JDK1.6用的JDBC

    7. **批处理**:JDBC提供批处理功能,可以一次性发送多条SQL语句,提高效率。 8. **结果集处理**:通过ResultSet对象获取查询结果,可以迭代遍历记录,也可以通过`next()`方法逐行读取。 9. **异常处理**:使用`...

    jdbc开发教程pdf

    为了提高性能,教程还将介绍JDBC的批处理和连接池。批处理允许一次性发送多个SQL命令,减少网络通信开销。而连接池则管理数据库连接,避免频繁创建和销毁连接,从而优化资源利用。 在高级主题中,读者将学习到...

    JDBC详解(连接操作数据库、处理大数据、批处理)

    ### JDBC详解:连接操作数据库、处理大数据、批处理 #### 一、JDBC简介 JDBC,全称为Java DataBase Connectivity(Java数据库连接),是Sun公司(现已被Oracle收购)为了解决不同数据库间的操作差异性而设计的一套...

Global site tag (gtag.js) - Google Analytics