千家信息网

MySQL JDBC Statement.executeBatch实践问题是怎样的

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,这篇文章将为大家详细讲解有关MySQL JDBC Statement.executeBatch实践问题是怎样的,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的
千家信息网最后更新 2026年11月03日MySQL JDBC Statement.executeBatch实践问题是怎样的

这篇文章将为大家详细讲解有关MySQL JDBC Statement.executeBatch实践问题是怎样的,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

MySQL JDBC Statement.executeBatch实践(执行效率低)

现在很少使用原生jdbc去实现代码, 最近在测试MySQL批处理数据遇到一个问题: 执行Statement.executeBatch时效率极其低下(插入10000条数据), 断点调试时在此处停顿很长时间(908712ms)

数据版本:

select version();// 5.7.17-11-V2.0R530D002-20190816-1203-log

数据库表:

CREATE TABLE `t_user` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `user_name` varchar(64) DEFAULT NULL,  `age` smallint(6) DEFAULT NULL,  `salary` decimal(10,2) DEFAULT NULL,  `max_size` int(11) DEFAULT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;

测试代码如下:

public class BatchTest {    public static void main(String[] args) throws SQLException, ClassNotFoundException {        batch("com.mysql.cj.jdbc.Driver",                "jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useUnicode=true&useSSL=false&allowMultiQueries=true",                "root", "123456");    }    private static void batch(String driver, String url, String username, String password) throws ClassNotFoundException, SQLException {        // jdbc driver: mysql-connector-java:8.0.21        Class.forName(driver);        Connection conn = DriverManager.getConnection(url, username, password);        conn.setAutoCommit(false);         PreparedStatement pstmt = conn.prepareStatement("select * from dual");        for(int i = 1; i <= 10000; i++){            String batchSql = "insert into t_user(user_name, age, salary, max_size) values (" +                    "'name" + i + "'," + i + "," + i + "," + i +                    ")";            pstmt.addBatch(batchSql);        }        long start = System.currentTimeMillis();        // 执行耗时很长        int[] rs = pstmt.executeBatch();        conn.commit();        // total ======> 908712        System.out.println("total ======> " + (System.currentTimeMillis() - start));    }}

原因

  1. addBatch() 是在PreparedStatement定义的, addBatch(String) 是在Statement定义的,

  2. MySQL JDBC驱动在默认情况下使用预编译会无视executeBatch()语句, 把我们期望批量执行的一组sql语句拆散, 一条一条地发给MySQL数据库, 直接造成较低的性能.

  3. batchHasPlainStatements=true, 即使用PreparedStatement时使用了Statement.addBatch(String), 不执行批处理操作, 一条一条地发给MySQL数据库, 直接造成较低的性能.(确使用方式: PreparedStatement + addBatch(), Statement + addBatch(sql))

JDBC驱动源码:

public class ClientPreparedStatement extends com.mysql.cj.jdbc.StatementImpl implements JdbcPreparedStatement {    /**     * Does the batch (if any) contain "plain" statements added by     * Statement.addBatch(String)?     *      * If so, we can't re-write it to use multi-value or multi-queries.     */    protected boolean batchHasPlainStatements = false;    // ......    protected long[] executeBatchInternal() throws SQLException {            synchronized (checkClosed().getConnectionMutex()) {                    if (this.connection.isReadOnly()) {                    throw new SQLException(Messages.getString("PreparedStatement.25") + Messages.getString("PreparedStatement.26"),                            MysqlErrorNumbers.SQL_STATE_ILLEGAL_ARGUMENT);                }                    if (this.query.getBatchedArgs() == null || this.query.getBatchedArgs().size() == 0) {                    return new long[0];                }                    // we timeout the entire batch, not individual statements                int batchTimeout = getTimeoutInMillis();                setTimeoutInMillis(0);                    resetCancelledState();                    try {                    statementBegins();                        clearWarnings();                     // 1. batchHasPlainStatements 包含原始sql语句                     // 2. rewriteBatchedStatements 使用批量                    if (!this.batchHasPlainStatements && this.rewriteBatchedStatements.getValue()) {                            if (((PreparedQuery) this.query).getParseInfo().canRewriteAsMultiValueInsertAtSqlLevel()) {                            return executeBatchedInserts(batchTimeout);                        }                            if (!this.batchHasPlainStatements && this.query.getBatchedArgs() != null                                && this.query.getBatchedArgs().size() > 3 /* cost of option setting rt-wise */) {                            return executePreparedBatchAsMultiStatement(batchTimeout);                        }                    }                        return executeBatchSerially(batchTimeout);                } finally {                    this.query.getStatementExecuting().set(false);                        clearBatch();                }            }    }    // ......}

修正:

  1. 在连接url加上&rewriteBatchedStatements=true, 如: jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useUnicode=true&useSSL=false&allowMultiQueries=true&rewriteBatchedStatements=true

  2. 使用Statement.addBatch()替换Statement.addBatch(String)

public class BatchTest {    public static void main(String[] args) throws SQLException, ClassNotFoundException {        batch("com.mysql.cj.jdbc.Driver",                "jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useUnicode=true&useSSL=false&allowMultiQueries=true&rewriteBatchedStatements=true",                "root", "123456");    }    private static void batch(String driver, String url, String username, String password) throws ClassNotFoundException, SQLException {        Class.forName(driver);        Connection conn = DriverManager.getConnection(url, username, password);        conn.setAutoCommit(false);        String pSql = "insert into t_user(user_name, age, salary, max_size) values (?, ?, ?, ?)";        PreparedStatement pstmt =conn.prepareStatement(pSql);        for(int i = 1; i <= 10000; i++){            try {                pstmt.setString(1, "name" + i);                pstmt.setInt(2, i);                pstmt.setInt(3, i);                pstmt.setInt(4, i);                pstmt.addBatch();            } catch (SQLException e) {                e.printStackTrace();            }        }        long start = System.currentTimeMillis();        int[] rs = pstmt.executeBatch();        conn.commit();        // total ======> 2598        System.out.println("total ======> " + (System.currentTimeMillis() - start));    }}

关于MySQL JDBC Statement.executeBatch实践问题是怎样的就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

数据 问题 实践 数据库 语句 代码 内容 性能 文章 是在 更多 知识 篇文章 测试 驱动 不错 低下 原始 原因 情况 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 苏州找大状互联网科技有限公司 科技互联网公司装修 互联网中国科技 关于新基建和互联网科技 深圳科技互联网 鑫亿盛互联网科技 互联网科技论文 广州互联网络科技有限公司 苏州互联网科技贷款公司 海南购全球互联网科技 海南科技产业互联网平台 互联网科技公司需要的职位 受益于互联网科技的高速发展 移动互联网科技公司 速维有品互联网信息科技(苏州)有限公司 翼展科技 首家互联网医院 领航科技大厦互联网公司 广西科技产业互联网是什么 上海旺乐尼互联网科技有限公司 互联网 科技节活动 微视频大赛 互联网科技股票 成都仁贤领冠互联网科技有限公司 济南和联互联网科技有限公司 天速互联网络科技有限公司 新华互联网科技2019 承德科技产业互联网发展 现代互联网科技股 晓花互联网科技有限公司网址 华夏恒生科技与互联网科技 互联网相关科技技术
0