`
yysct2005
  • 浏览: 91380 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

JDBC Update深度优化

阅读更多
JDBC Update深度优化
 
Update是数据同步过程中一个不可缺少的操作,这里所讨论的更新并非写一个update语句更新了一批数据,如果是这样,就没必要写此文章了。
这里所讨论的更新是根据查询对比,决定是否更新、删除等,甚至还要处理一些相关业务。对于这样的操作,JDBC比任何方式的效率都好。这里所谓的批量,是说有一大批这样数据要通过查询检查,然后去做更新、删除操作。
 
为了进行测试,将问题抽象简化,根据查询更新、删除。
 
环境:
MySQL 5.1
RedHat Linux AS 5
JavaSE 1.5
DbConnectionBroker 微型数据库连接池
 
优化的策略:
1、使用连接池
2、尽可能减少数据库的链接和检索次数
 
做到这两个方面,就达到优化的的目标了。
 
SQL脚本
DROP TABLE IF EXISTS tuser;    

CREATE TABLE tuser (    
        id bigint(20) NOT NULL AUTO_INCREMENT,    
        name varchar(12) DEFAULT NULL,    
        remark varchar(24) DEFAULT NULL,    
        createtime datetime DEFAULT NULL,    
        updatetime datetime DEFAULT NULL,    
        PRIMARY KEY (id)    
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
 
下面是优化实现代码:
import java.io.IOException;
import java.sql.*;

/**
* JDBC批量Update深度优化
*
* @author leizhimin 2009-7-30 8:38:33
*/

public class TestQuery {
        public static DbConnectionBroker myBroker = null;

        static {
                try {
                        myBroker = new DbConnectionBroker("com.mysql.jdbc.Driver",
                                        "jdbc:mysql://192.168.104.163:3306/testdb",
                                        "vcom", "vcom", 2, 4,
                                        "c:\\testdb.log", 0.01);
                } catch (IOException e) {
                        e.printStackTrace();
                }
        }

        /**
         * 初始化测试环境
         *
         * @throws SQLException 异常时抛出
         */

        public static void init() throws SQLException {
                Connection conn = myBroker.getConnection();
                conn.setAutoCommit(false);
                Statement stmt = conn.createStatement();
                stmt.addBatch("DROP TABLE IF EXISTS tuser");
                stmt.addBatch("CREATE TABLE tuser (\n" +
                                "    id bigint(20) NOT NULL AUTO_INCREMENT,\n" +
                                "    name varchar(12) DEFAULT NULL,\n" +
                                "    remark varchar(24) DEFAULT NULL,\n" +
                                "    createtime datetime DEFAULT NULL,\n" +
                                "    updatetime datetime DEFAULT NULL,\n" +
                                "    PRIMARY KEY (id)\n" +
                                ") ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8");
                stmt.executeBatch();
                conn.commit();
                System.out.println("--------数据库所支持的ResultSet的类型---------");
                System.out.println("ResultSet.TYPE_FORWARD_ONLY\t\t\t:"+conn.getMetaData().supportsResultSetType(ResultSet.TYPE_FORWARD_ONLY));
                System.out.println("ResultSet.TYPE_SCROLL_INSENSITIVE\t:"+conn.getMetaData().supportsResultSetType(ResultSet.TYPE_SCROLL_INSENSITIVE));
                System.out.println("ResultSet.TYPE_SCROLL_SENSITIVE\t\t:"+conn.getMetaData().supportsResultSetType(ResultSet.TYPE_SCROLL_SENSITIVE));
                myBroker.freeConnection(conn);
        }

        /**
         * n条预定义SQL插入
         *
         * @throws Exception 异常时抛出
         */

        public static void initData(int n) throws Exception {
                init();         //初始化环境
                Long start = System.currentTimeMillis();
                String sql = "" +
                                "insert into testdb.tuser\n" +
                                "    (name, remark, createtime, updatetime)\n" +
                                "values\n" +
                                "    (?, ?, ?, ?)";
                for (int i = 0; i < n; i++) {
                        Connection conn = myBroker.getConnection();
                        conn.setAutoCommit(false);
                        PreparedStatement pstmt = conn.prepareStatement(sql);
                        pstmt.setString(1, RandomToolkit.generateString(12));
                        pstmt.setString(2, RandomToolkit.generateString(24));
                        pstmt.setDate(3, new Date(System.currentTimeMillis()));
                        pstmt.setDate(4, new Date(System.currentTimeMillis()));
                        pstmt.executeUpdate();
                        conn.commit();
                        pstmt.close();
                        myBroker.freeConnection(conn);
                }
                Long end = System.currentTimeMillis();
                System.out.println("单条执行" + n + "条Insert操作,共耗时:" + (end - start) / 1000f + "秒!");
        }

        /**
         * 查询一条数据,并更新该条数据
         *
         * @throws SQLException
         */

        public static void testQueryOne4Update() throws SQLException {
                String query_sql = "select id, name, remark, createtime, updatetime\n" +
                                "    from testdb.tuser where id = 1";
                Connection conn = myBroker.getConnection();
                conn.setAutoCommit(false);
                //注意结果集的参数配置
                Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE, ResultSet.CLOSE_CURSORS_AT_COMMIT);
                System.out.println("连接是否为只读模式:" + conn.isReadOnly());
                System.out.println("查询使用的SQL所对应的本地SQL脚本:" + conn.nativeSQL(query_sql));
                ResultSet rs = stmt.executeQuery(query_sql);
                while (rs.next()) {    //一行数据,本while可以省略
                        //更新数据的name列
                        rs.updateString("name", "new name");
                        //保存更新行
                        rs.updateRow();
                }
                conn.commit();
                myBroker.freeConnection(conn);
        }

        /**
         * 查询多条记录并做更新操作
         *
         * @throws SQLException
         */

        public static void testQueryMany4Update() throws SQLException {
                String query_sql = "select id, name, remark, createtime, updatetime\n" +
                                "    from testdb.tuser where id >2 and id<5";
                Connection conn = myBroker.getConnection();
                conn.setAutoCommit(false);
                Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE, ResultSet.CLOSE_CURSORS_AT_COMMIT);
                ResultSet rs = stmt.executeQuery(query_sql);
                //循环逐条更新查询结果集数据
                while (rs.next()) {
                        //更新数据的name列
                        rs.updateString("name", "lavasoft25");
                        rs.updateDate("updatetime", new Date(System.currentTimeMillis()));
                        //保存更新行
                        rs.updateRow();
                }
                System.out.println(conn.isReadOnly());
                System.out.println(conn.nativeSQL(query_sql));
                conn.commit();
                myBroker.freeConnection(conn);
        }

        /**
         * 查询一条记录并做插入操作
         *
         * @throws SQLException
         */

        public static void testQueryOne4Insert() throws SQLException {
                String query_sql = "select id, name, remark, createtime, updatetime\n" +
                                "    from testdb.tuser where id = 1 ";
                Connection conn = myBroker.getConnection();
                conn.setAutoCommit(false);
                Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE, ResultSet.CLOSE_CURSORS_AT_COMMIT);
                ResultSet rs = stmt.executeQuery(query_sql);
                //将结果集指针移动到可插入的行(这行是在内存中的一个虚拟行)
                rs.moveToInsertRow();
                //设定行各个字段的数据
                rs.updateString(2, "熔岩");
                rs.updateString(3, "ttt");
                rs.updateDate(4, new Date(System.currentTimeMillis()));
                rs.updateDate(5, new Date(System.currentTimeMillis()));
                //插入行数据到该表中
                rs.insertRow();
                //指针复位:将指针移动到执行moveToInsertRow()之前的位置
                rs.moveToCurrentRow();
                conn.commit();
                myBroker.freeConnection(conn);
        }

        /**
         * 查询一批数据,并做插入操作
         *
         * @throws SQLException
         */

        public static void testQueryMany4Insert() throws SQLException {
                String query_sql = "select id, name, remark, createtime, updatetime\n" +
                                "    from testdb.tuser where id >4 and id<8";
                Connection conn = myBroker.getConnection();
                conn.setAutoCommit(false);
                Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE, ResultSet.CLOSE_CURSORS_AT_COMMIT);
                ResultSet rs = stmt.executeQuery(query_sql);
                while (rs.next()) {
                        //将结果集指针移动到可插入的行(这行是在内存中的一个虚拟行)
                        rs.moveToInsertRow();
                        //设定行各个字段的数据
                        rs.updateString(2, "lavasoft3");
                        rs.updateString(3, "ttt");
                        rs.updateDate(4, new Date(System.currentTimeMillis()));
                        rs.updateDate(5, new Date(System.currentTimeMillis()));
                        //插入行数据到该表中
                        rs.insertRow();
                        //指针复位:将指针移动到执行moveToInsertRow()之前的位置
                        rs.moveToCurrentRow();
                        //将指针从当前位置下移一行
                        rs.next();
                }
                conn.commit();
                myBroker.freeConnection(conn);
        }

        /**
         * 查询一条数据,并做插入操作
         *
         * @throws SQLException
         */

        public static void testQueryOne4Delete() throws SQLException {
                String query_sql = "select id, name, remark, createtime, updatetime\n" +
                                "    from testdb.tuser where id=8";
                Connection conn = myBroker.getConnection();
                conn.setAutoCommit(false);
                Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE, ResultSet.CLOSE_CURSORS_AT_COMMIT);
                ResultSet rs = stmt.executeQuery(query_sql);
                //将指针移动到要删除的行上
                rs.next();
                //从此 ResultSet 对象和底层数据库中删除当前行。指针不位于插入行上时不能调用此方法。
                rs.deleteRow();
                rs.next();
                conn.commit();
                myBroker.freeConnection(conn);
        }

        /**
         * 查询一批数据,并做插入操作
         *
         * @throws SQLException
         */

        public static void testQueryMany4Delete() throws SQLException {
                String query_sql = "select id, name, remark, createtime, updatetime\n" +
                                "    from testdb.tuser where id>1";
                Connection conn = myBroker.getConnection();
                conn.setAutoCommit(false);
                Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE, ResultSet.CLOSE_CURSORS_AT_COMMIT);
                ResultSet rs = stmt.executeQuery(query_sql);
                while (rs.next()) {
                        //从此 ResultSet 对象和底层数据库中删除当前行。指针不位于插入行上时不能调用此方法。
                        System.out.println(rs.getRow());
                        rs.deleteRow();
                        rs.beforeFirst();
                }
                conn.commit();
                myBroker.freeConnection(conn);
        }

        public static void main(String[] args) throws SQLException {
                init();
//                testQueryMany4Delete();
        }
}
 
总结:
 
1、优化思想就是尽量减少数据库连接和请求。根据查询结果,直接更改结果,然后保存实现了数据的更新,一个连接做多件事情,性能相比先查询结果集合,然后构建更新SQL再执行要好很多。删除操作也类似。
2、优化的关键就是在查询结果集上做文章,并不是所有的结果集都支持这样的更新和删除操作,在构建Statement对象的时候,几个ResultSet参数需要特别注意:
 
TYPE_FORWARD_ONLY    
                    该常量指示指针只能向前移动的 ResultSet 对象的类型,默认类型。只允许向前一条一条的访问,并且不会受到其他用户对该数据库所作更改的影响。
。    
TYPE_SCROLL_INSENSITIVE    
                    该常量指示可滚动但通常不受其他的更改影响的 ResultSet 对象的类型,允许在列表中向前或向后移动,甚至可以进行特定定位,不会受到其他用户对该数据库所作更改的影响。
。    
TYPE_SCROLL_SENSITIVE    
                    该常量指示可滚动并且通常受其他的更改影响的 ResultSet 对象的类型,像TYPE_SCROLL_INSENSITIVE一样,允许在记录中定位。这种类型受到其他用户所作更改的影响。如果用户在执行完查询之后删除一个记录,那个记录将从ResultSet中消失。类似的,对数据值的更改也将反映在ResultSet中。
    
CONCUR_READ_ONLY    
                    该常量指示不可以更新的 ResultSet 对象的并发模式,适合只查询,不对结果集修改的操作。    
CONCUR_UPDATABLE    
                    该常量指示可以更新的 ResultSet 对象的并发模式,适合对查询结果集做更新、删除的操作。 
   
CLOSE_CURSORS_AT_COMMIT    
                    该常量指示调用 Connection.commit 方法时应该关闭 ResultSet 对象,一般情况下都应该如此。    
HOLD_CURSORS_OVER_COMMIT    
                    该常量指示调用 Connection.commit 方法时不应关闭 ResultSet 对象,很少用到。
 
3、更新查询结果集数据能否真正持久化,与JDBC驱动程序的完善程度有关,不是所有的JDBC驱动程序都支持结果集的高级特性。可以通过DatabaseMetaData来查询驱动程序的支持情况。
 

本文出自 “熔 岩” 博客,转载请与作者联系!

分享到:
评论

相关推荐

    jdbc工具整理

    **JDBC工具整理** 在Java开发中,JDBC...总的来说,这个"jdbc工具 v3"资源包含了对JDBC的深度封装,旨在简化数据库操作,提高开发效率。通过理解上述知识点,可以更好地利用这些工具,实现高效、安全的数据库编程。

    SpringStudy_JDBC.zip

    《Spring与JDBC深度解析》 在Java世界中,Spring框架以其强大的功能和灵活的架构设计,成为企业级应用开发的首选。而JDBC(Java Database Connectivity)作为Java与数据库交互的标准接口,是每个Java开发者必备的...

    深度学习JSP留言板 v0.1.1

    数据库操作通常通过Java的JDBC(Java Database Connectivity)API实现,包括连接数据库、执行SQL语句(如INSERT、SELECT、UPDATE、DELETE)、处理结果集等。 用户接口设计是另一个关键点。一个良好的留言板界面应...

    springsource-tool-suite-3.4.0.RELEASE-e4.3.1-updatesite.zip

    ST Suite集成了Spring Framework的所有核心模块,包括Spring MVC、Spring Web Flow、Spring AOP、Spring JDBC等,为开发者提供了一站式的开发解决方案。它内置了Spring Roo,一个快速应用开发(RAD)工具,可以自动...

    Java数据库编程宝典

    《Java数据库编程宝典》是一本专为Java开发者设计的深度学习数据库编程的教程,旨在帮助读者提升在数据库领域的技能,实现高效、稳定的数据库应用程序开发。本书覆盖了从基础概念到高级技术,全面讲解了Java如何与...

    网站数据采集分析

    Struts2提供了一种规范化的开发方式,JDBC实现了数据库的高效访问,分页封装优化了用户体验,而增删改查封装和数据挖掘则为数据处理和业务洞察提供了有力的支持。通过解压并分析"datacenter.zip"和"wxcs_centerdemo....

    SQLExplorer

    它支持基本的SQL操作,如SELECT、INSERT、UPDATE、DELETE,以及更复杂的JOIN、SUBQUERY和存储过程调用。查询结果将以表格形式展示,便于查看和分析。 **4. 对象浏览与管理** SQLExplorer还允许用户浏览和管理数据库...

    hibernate-release-5.1.12.Final.zip

    《Hibernate 5.1.12 Final:Java ORM框架的核心技术深度解析》 Hibernate,作为Java领域中的一个著名对象关系映射(ORM)框架,极大地简化了数据库操作,使得开发者可以更加专注于业务逻辑而非繁琐的数据处理。本次...

    hibernate-release-5.0.7.Final的html文档说明

    《Hibernate 5.0.7.Final:深度解析与实战指南》 Hibernate,作为Java领域中最流行的ORM(对象关系映射)框架之一,为开发者提供了便捷的数据库操作方式,极大地提高了开发效率。5.0.7.Final是Hibernate的一个稳定...

    华育国际oracle培训教程

    Oracle 9i是Oracle数据库的一个重要版本,它引入了对Java的深度集成,使得开发者可以直接在数据库中进行Java应用程序的开发和执行。这部分教程可能涵盖JDBC(Java Database Connectivity)的使用,以及如何利用...

    ibatis详细解答

    Transaction Manager ⑵节点 - 定义事务管理器,这里使用JDBC类型的事务管理,意味着Ibatis将直接使用JDBC API来管理事务。 DataSource ⑶节点 - 数据源配置,包括数据库驱动、连接URL、用户名、密码等。这里还展示...

    hibernate-release-5.0.12.Final.rar

    《Hibernate 5.0.12.Final:企业级Java持久化框架深度解析》 Hibernate,作为Java领域中广泛使用的对象关系映射(ORM)框架,一直以来都是开发人员的重要工具,尤其是在处理数据库交互时。本篇文章将围绕"hibernate...

    OracleOracleExpert_one-on-one_Oracle

    1. SQL基础:介绍SQL语言的基本概念,包括SELECT语句、DML操作(INSERT、UPDATE、DELETE)、DDL(数据定义语言)以及查询优化。 2. PL/SQL:Oracle的程序化SQL,用于编写存储过程、函数、触发器和包,实现更复杂的...

    JAVA MySql宠物商店ACCP8.0

    《JAVA MySql宠物商店ACCP8.0:深度解析与实践》 在信息技术领域,Java和MySQL是两个不可或缺的重要工具,广泛应用于各种类型的软件开发,尤其是Web应用。本项目"JAVA MySql宠物商店ACCP8.0"就是将这两个技术结合,...

    Hibernate文档

    1. 合理设计实体关系,避免深度嵌套的关联导致的性能问题。 2. 使用事务管理,保证数据一致性。 3. 慎用级联操作,避免引发不必要的数据更新。 4. 利用缓存优化,但要注意缓存同步和数据一致性问题。 总结,...

    Hibernate 参数设置一览表(强烈推荐)

    16. **hibernate.max_fetch_depth**:限制了级联加载的深度,防止深度递归导致性能下降。 17. **hibernate.default_batch_fetch_size**:默认的批处理获取大小,适用于未指定批处理大小的关联。 18. **hibernate....

    Hibernate配置文件

    常见的值有`create`(每次启动应用时新建表)、`update`(根据实体类更新表结构)和`validate`(检查表结构是否匹配)。 3. **缓存配置** - `cache.provider_class`: 指定缓存提供者,如`...

    hibernate.rar

    《Hibernate:Java持久化框架深度解析》 Hibernate是一款强大的Java对象关系映射(ORM)框架,它极大地简化了数据库操作,让开发者可以专注于业务逻辑,而无需过多关注底层SQL的编写。本文将深入探讨Hibernate的...

    Hibernate开发资料

    《Hibernate开发资料》是一份深度剖析Hibernate技术的综合性文档,旨在为Java开发人员以及DAO架构设计者提供详尽的学习和参考资料。Hibernate作为一款强大的对象关系映射(ORM)框架,它简化了Java应用程序与数据库...

    Hibernate JPA

    - **性能优化**: 通过配置文件中的各项参数,可以对性能进行精细调优。 #### 三、总结 Hibernate JPA作为一种成熟且广泛使用的ORM解决方案,不仅简化了Java应用程序中对象与关系型数据库之间的交互,还为开发者...

Global site tag (gtag.js) - Google Analytics