MySql 如何急速插入百萬數據 批量插入 Statement PreparedStatement

方法一:Statement使用如下

import java.sql.*;

public class InsertMoreStatement {

    // MySQL 8.0 以上版本 - JDBC 驅動名及數據庫 URL
    static final String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver";
    static final String DB_URL = "jdbc:mysql://localhost:3308/weqqq?useSSL=false&serverTimezone=UTC&useLocalSessionState=true";


    // 數據庫的用戶名與密碼,需要根據自己的設置
    static final String USER = "root";
    static final String PASS = "root";

    public static void main(String[] args) {
        Connection con = null;
        try {
            con = DriverManager.getConnection(DB_URL,USER,PASS);

            Statement statement = (Statement)con.createStatement();

            con.setAutoCommit(false);
            long startTime = System.currentTimeMillis();
            System.out.println("開始……");
            for (int i=0;i<1000000;i++)
            {
                statement.execute(String.format("INSERT INTO `pi_liang_insert`(value) VALUES ( '%s');" , "lt_"+ i));
            }
            long endTime  = System.currentTimeMillis();
            con.commit();
            System.out.println("用時:" + (endTime-startTime));
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

    }

}

調用結果

用時接近4分鐘

我們可以查看日誌。其過程爲將插入命令調用100萬次

注意 url裏的  useLocalSessionState=true,該參數設置爲true可提高很多速率,否則每條插入語句前都會有一句狀態確認的查詢,如下圖

因爲以上方法效率趕人,故在批量插入時並不推薦


方法二PreparedStatement:


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

public class InsertMorePreparedStatement {

    // MySQL 8.0 以下版本 - JDBC 驅動名及數據庫 URL
//    static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
//    static final String DB_URL = "jdbc:mysql://localhost:3308/RUNOOB";

    // MySQL 8.0 以上版本 - JDBC 驅動名及數據庫 URL
    static final String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver";
    static final String DB_URL = "jdbc:mysql://localhost:3308/weqqq?useSSL=false&serverTimezone=UTC&useLocalSessionState=true&rewriteBatchedStatements=true";


    // 數據庫的用戶名與密碼,需要根據自己的設置
    static final String USER = "root";
    static final String PASS = "root";
    static String sql = "INSERT INTO `pi_liang_insert`(value) VALUES ( ?)";

    public static void main(String[] args) {
        Connection con = null;
        try {
            con = DriverManager.getConnection(DB_URL,USER,PASS);

            PreparedStatement preparedStatement = con.prepareStatement(sql);

            con.setAutoCommit(false);
            long startTime = System.currentTimeMillis();
            System.out.println("開始……");
//            for (int i=0;i<100000;i++)
//            {
//                preparedStatement.setString(1,"asfsdfsdf"+i);
//                preparedStatement.addBatch();
//            }
//            preparedStatement.executeBatch();
            for (int j=0;j<100;j++)//防止最大命令字符數溢出
            {
                for (int i=0;i<10000;i++)
                {
                    preparedStatement.setString(1,"lt_"+(i+j*10000));
                    preparedStatement.addBatch();
                }
                preparedStatement.executeBatch();
            }
            long endTime  = System.currentTimeMillis();
            con.commit();
            System.out.println("用時:" + (endTime-startTime) + "毫秒");
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        System.exit(0);
    }

}

調用結果如下:

百萬數據插入僅需要6.8秒。

我們來看下日誌

插入命令變爲 批量插入語法:

INSERT INTO `pi_liang_insert`(value) VALUES ( 'xxxxxxx'),('xxxxxxxx')………………

不再逐條插入,故速率提升。

在這個裏我分100次,一次提交10000條數據,主要是因爲,命令的字節包有長度限制。如果字節包長度過大,可修改數據庫裏的參數

查看max_allowed_packet:

mysql> show variables like 'max_allowed_packet';
+--------------------+----------+
| Variable_name      | Value    |
+--------------------+----------+
| max_allowed_packet | 15728640 |
+--------------------+----------+

修改max_allowed_packet:

mysql> set global max_allowed_packet=1024*10;

 

注意rewriteBatchedStatements必須設置爲ture,否則依然是逐條插入

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章