如何使用java代碼一次性往數據插入10W條數據


1. 場景 : 往數據庫插入10W條記錄 

2. 思考方案 : 單純的我們這里不涉及其他任何操作,我們只是想生成一個10W條記錄而已,中間無其他步驟,得到的效果如下圖所示,

而我們又不會mysql腳本啊之類的,那我們不如用java來實現,用jdbc的批次操作來完成 ,博客借鑒自: 

   https://blog.csdn.net/summeranhx/article/details/81583575?utm_source=blogxgwz0 

  實現的效果圖為 : 

  

3. 代碼為 : 

  

package root.report.control.dict;

import org.apache.ibatis.session.SqlSession;
import root.report.db.DbFactory;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;

/**
 * @Auther: pccw
 * @Date: 2018/10/29 17:45
 * @Description:
 */
/*

往自己本地mysql 當中插入10W條記錄

 */
public class TestTwo {

    public static void main(String args[]){
        SqlSession sqlSession = DbFactory.Open(DbFactory.FORM);  // 本地mysql數據庫
        insert(sqlSession);
    }

    public static void insert(SqlSession sqlSession){
        Connection conn = sqlSession.getConnection();
        // 開始時間
        Long begin = new Date().getTime();
        // sql前綴
        String prefix = "INSERT INTO test_dict (code,name) VALUES ";
        try {
            // 保存sql后綴
            StringBuffer suffix = new StringBuffer();
            // 設置事務為非自動提交
            conn.setAutoCommit(false);
            // 比起st,pst會更好些
            PreparedStatement pst = (PreparedStatement) conn.prepareStatement("");//准備執行語句
            // 外層循環,總提交事務次數
            for (int i = 1; i <= 5; i++) {
                suffix = new StringBuffer();
                // 第j次提交步長
                if(i == 1) {
                    for (int j = 1; j < 10; j++) {
                        // 構建SQL后綴
                        suffix.append("(" + j+","+"'0000" +j+"'),");
                    }
                }else if(i == 2) {
                    for (int j = 10; j < 100; j++) {
                        // 構建SQL后綴
                        suffix.append("(" + j+","+"'000" +j+"'),");
                    }
                }else if(i == 3) {
                    for (int j = 100; j < 1000; j++) {
                        // 構建SQL后綴
                        suffix.append("(" + j+","+"'00" +j+"'),");
                    }
                }else if(i == 4) {
                    for (int j = 1000; j < 10000; j++) {
                        // 構建SQL后綴
                        suffix.append("(" + j+","+"'0" +j+"'),");
                    }
                }else {
                    for (int j = 10000; j <= 99999; j++) {
                        // 構建SQL后綴
                        suffix.append("(" + j+","+"'" +j+"'),");
                    }
                }


                // 構建完整SQL
                String sql = prefix + suffix.substring(0, suffix.length() - 1);
                // 添加執行SQL
                pst.addBatch(sql);
                // 執行操作
                pst.executeBatch();
                // 提交事務
                conn.commit();
                // 清空上一次添加的數據
                suffix = new StringBuffer();
            }
            // 頭等連接
            pst.close();
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        // 結束時間
        Long end = new Date().getTime();
        // 耗時
        System.out.println("10萬條數據插入花費時間 : " + (end - begin) / 1000 + " s");
        System.out.println("插入完成");
    }


}

  不難看出,代碼沒什么含金量,代碼着重在於下面2處操作: 

  

  // 添加執行SQL
                pst.addBatch(sql);
                // 執行操作
                pst.executeBatch();

4. 我們再改寫成用多線程的方式試試 : 

  改寫成多線程 方案則要考慮到使用何種線程池 ? 線程池線程都執行完才能繼續執行下一步驟,在此期間怎樣感知線程執行完畢 ? 

  沒錯,我們這在這里使用了  newFixedThreadPool  這個線程池,這是直接規划出多少個線程,然后我們怎樣讓線程執行完畢再執行其他的?

  沒錯,我們直接使用  

final CountDownLatch count = new CountDownLatch(5);
CountDownLatch  這個並發包輔助類 -》當我們線程執行完一個任務之后,count.countDown(); -》 同時對於fixedThreadPool 這個變量
要使用 synchronized 來進行鎖定,然后在整個方法之外 對 count 變量進行 await()喚醒操作,繼續執行下列步驟。
好了,廢話少說,下面貼出代碼 :
package root.report.control.dict;

import org.apache.ibatis.session.SqlSession;
import root.report.db.DbFactory;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Auther: pccw
 * @Date: 2018/10/29 17:45
 * @Description:
 */
/*

往自己本地mysql 當中插入10W條記錄

 */
public class TestTwo {

    public static void main(String args[]) throws SQLException {
        SqlSession sqlSession = DbFactory.Open(DbFactory.FORM);
        // insert(sqlSession);
        insertTwo(sqlSession);
    }
 // 多線程案例  使用fix線程  規定為5個
    public static void insertTwo(SqlSession sqlSession) throws SQLException {

        Connection conn = sqlSession.getConnection();
        // 開始時間
        Long begin = new Date().getTime();


        final StringBuffer suffix = new StringBuffer();
        // sql前綴
        String prefix = "INSERT INTO test_dict (code,name) VALUES ";
        // 設置事務為非自動提交
        conn.setAutoCommit(false);
        // 比起st,pst會更好些
        PreparedStatement pst = (PreparedStatement) conn.prepareStatement("");//准備執行語句

        final CountDownLatch count = new CountDownLatch(5);
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
        synchronized (fixedThreadPool) {
            for (int i = 1; i <= 5; i++) {
                final int index = i;
                if (i == 1) {
                    fixedThreadPool.execute(new Runnable() {
                        @Override
                        public void run() {
                            for (int j = 1; j < 10; j++) {
                                // 構建SQL后綴
                                suffix.append("(" + j + "," + "'0000" + j + "'),");
                            }
                            count.countDown();
                        }
                    });
                } else if (i == 2) {
                    fixedThreadPool.execute(new Runnable() {
                        @Override
                        public void run() {
                            for (int j = 10; j < 100; j++) {
                                // 構建SQL后綴
                                suffix.append("(" + j + "," + "'000" + j + "'),");
                            }
                            count.countDown();
                        }
                    });
                } else if (i == 3) {
                    fixedThreadPool.execute(new Runnable() {
                        @Override
                        public void run() {
                            for (int j = 100; j < 1000; j++) {
                                // 構建SQL后綴
                                suffix.append("(" + j + "," + "'00" + j + "'),");
                            }
                            count.countDown();
                        }
                    });
                } else if (i == 4) {
                    fixedThreadPool.execute(new Runnable() {
                        @Override
                        public void run() {
                            for (int j = 1000; j < 10000; j++) {
                                // 構建SQL后綴
                                suffix.append("(" + j + "," + "'0" + j + "'),");
                            }
                            count.countDown();
                        }
                    });
                } else {
                    fixedThreadPool.execute(new Runnable() {
                        @Override
                        public void run() {
                            for (int j = 10000; j <= 99999; j++) {
                                // 構建SQL后綴
                                suffix.append("(" + j + "," + "'" + j + "'),");
                            }
                            count.countDown();
                        }
                    });
                }
            }
        }
        try {
            count.await();
            // 構建完整SQL
            String sql = prefix + suffix.substring(0, suffix.length() - 1);

            // 添加執行SQL
            pst.addBatch(sql);
            // 執行操作
            pst.executeBatch();
            // 提交事務
            conn.commit();
            // 頭等連接
            pst.close();
            conn.close();
            // 結束時間
            Long end = new Date().getTime();

            System.out.println("10萬條數據插入花費時間 : " + (end - begin)  + " ms");
            System.out.println("插入完成");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            fixedThreadPool.shutdown();
        }
    }

    // 測試使用 fetch 按照指定規格讀取數據


}
多線程執行批量插入

    那么,其實我的機子是8G內存的,在上面非多線程模式執行代碼,花費了4S :

   

  而我們使用了多線程之后,發現連1S都不到,而且數據庫數量也都是對的:

  

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM