1. 程式人生 > >關於jdbc批處理的一些小問題

關於jdbc批處理的一些小問題

一個專案實現過程中難免遇到一些批量執行sql語句的情況,例如執行1萬條插入語句,如果使用傳統的插入方式則需要建立1萬次連線,一次傳送一條sql語句,這樣是及其浪費效能的,接下來通過三種不同的方式模擬批量的插入語句,程式碼如下:

package com.lsm1998.shop.test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.Statement;

public class JDBCTest
{
    static
    {
        try
        {
            //com.mysql.jdbc.Driver與com.mysql.cj.jdbc.Driver有啥不同?
            //com.mysql.jdbc.Driver 是 mysql-connector-java 5中的,
            //com.mysql.cj.jdbc.Driver 是 mysql-connector-java 6中的
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws Exception
    {
        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf-8&serverTimezone=UTC", "root", "123456");
        //test1(connection);
        //test2(connection);
        test3(connection);
    }

    /**
     * 常規提交
     * 耗時 31202ms
     *
     * @param connection
     * @throws Exception
     */
    private static void test1(Connection connection) throws Exception
    {
        Statement statement = connection.createStatement();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++)
        {
            String sql = "insert into v1(name) values('測試_" + i + "');";
            statement.execute(sql);
        }
        long end = System.currentTimeMillis();
        System.out.println("耗時=" + (end - start));
        statement.close();
    }

    /**
     * 採用事務提交
     * 耗時 4182ms
     *
     * @param connection
     * @throws Exception
     */
    private static void test2(Connection connection) throws Exception
    {
        connection.setAutoCommit(false);
        Statement statement = connection.createStatement();
        long start = System.currentTimeMillis();
        try
        {
            for (int i = 0; i < 10000; i++)
            {
                String sql = "insert into v1(name) values('測試_" + i + "');";
                statement.execute(sql);
            }
            connection.commit();
            statement.close();
        } catch (Exception e)
        {
            connection.rollback();
        }
        long end = System.currentTimeMillis();
        System.out.println("耗時=" + (end - start));
    }

    /**
     * 批處理提交
     * 耗時 2634ms(預編譯)
     *
     * @param connection
     * @throws Exception
     */
    private static void test3(Connection connection) throws Exception
    {
        connection.setAutoCommit(false);
        String sql = "insert into v1(name) values(?);";
        PreparedStatement ps = connection.prepareStatement(sql);
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++)
        {
            ps.setString(1, "測試_" + i);
            ps.addBatch();
        }
        ps.executeBatch();
        connection.commit();
        long end = System.currentTimeMillis();
        System.out.println("耗時=" + (end - start));
    }
}

首先宣告一下筆者的配置:

  1. mysql5.5;
  2. jdk11;
  3. 驅動 mysql-connector-java-8.0.13.jar;
  4. CPU i5-6200U;
  5. 記憶體4G;

開始筆者犯了一個嚴重的錯誤,就算以為批處理會自動開啟事務,最後測試結果為27秒,對此差點懷疑是假的批處理,最後抱著試一試的態度加入事務相關程式碼,果然如此,僅耗時不到3秒,最後結果評測:常規方式31秒,批處理不到3秒,同一個事務內不進行批處理需要4秒,好在問題是解決了,得出重要結論:批處理也要宣告事務!