批量插入的一萬種場景之二

在平常工做中,咱們常常會遇到各類各樣的需求,須要將數據插入到數據庫中,不過不一樣的需求用不一樣的插入寫法,這樣能提高很大的效率,這篇文章會根據不一樣的場景使用不一樣的批量插入代碼,你們之後遇到批量插入直接來我這裏粘貼就能夠了。java

 

場景一:sql

app中最多見的pv和uv接口,用戶每點擊一次都須要在數據庫中插入一條數據。這種狀況咱們不可能一直請求數據庫,確定會將數據先存到緩存或者隊列中,而後批量插入到數據庫。數據庫

 

上隊列代碼緩存

public void run() {
    startLog();
    while (!isInterrupted()) {
        List<T> list = new ArrayList<T>();
        preProcessor();
        try {
            long ts = 0;
            //每一百條批量插入一次
            for (int i = 0; i < 100; ) {
                T tmp = null;
                try {
                    tmp = queue.poll(5000, TimeUnit.MILLISECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (tmp != null) {
                    //記錄第一次添加數據後的時間
                    if (i++ == 0) {
                        ts = System.currentTimeMillis();
                    }
                    //處理
                    processor(list, tmp);
                    continue;
                }
                //有數據  且從第一次插入數據已通過了 設定時間 則 執行插入
                if (list.size() > 0 && System.currentTimeMillis() - ts >= BATCH_TIMEOUT) {
                    break;
                }
            }
            save(list);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

上mybatis代碼session

<insert id="batchInsert" parameterType="List">
    insert into dsc_user 
    (
        user_name, nick_name, mobile
    )
    values
    <foreach collection='list' item='item' index='index' separator=','>
        (
            #{item.userName,jdbcType=VARCHAR},#{item.nickName,jdbcType=VARCHAR},#{item.mobile,jdbcType=VARCHAR}
        )
    </foreach>
</insert>

注:這個地方不能把foreach標籤寫到外層,不然仍是會不停的建立關閉sqlsessionmybatis

 

場景二:app

某個功能導入數據老是千萬級別,如何最快的將數據插入到數據庫中ide

 

這種大數據量導入數據 和 小數據量導入是有很大區別的,一樣的代碼,小數據量導入能夠完美實現,但數據量大了以後就會出現各類各樣的問題大數據

 

首先,咱們要重視的是內存,若是要實現千萬級別的數據導入,JVM的堆內存必定要設置一個比較大的數值url

其次,要分段保存到數據庫,好比每1000條數據執行一次

最後,不要使用mybatis,由於myabtis封裝程度過高,解析SQL模板和SQL拼接會消耗大量時間,要使用原生的JDBC

 上代碼

public void insertBatch() {
    Connection conn = null;
    Statement statement = null;
    try {
        conn = DriverManager.getConnection(url, username, password);
        conn.setAutoCommit(false);
        statement = conn.createStatement();
        for (int i = 0; i < 10000000; i++) {
            String sql = "insert into dsc_user(user_name, nick_name, mobile)  
                          values ('"+i+"', '第"+i+"條數據', '158'+"+ i +")";
            //利用addBatch方法將SQL語句加入到stmt對象中
            statement.addBatch(sql);
            if (i % 1000 == 0 && i != 0) {
                //利用executeBatch方法執行1000條SQL語句
                statement.executeBatch();
                statement.clearBatch();
                conn.commit();
            }
        }
        statement.executeBatch();
        statement.clearBatch();
        conn.commit();
        close(); //關閉資源
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

通常狀況下,咱們不多遇到須要批量插入千萬級別數據的,因此批量插入只須要在mybatis中使用一下foreach標籤就能解決,以下代碼

public void insertBatch(List<CouponHistory> coupons){
    if (coupons == null || coupons.isEmpty()){
        return;
    }
    int index = 1000;
    int currentPageStart = 0;
    int currentPageEnd = 0;

    while (currentPageEnd < coupons.size()){
        currentPageStart = currentPageEnd;
        currentPageEnd = Math.min(currentPageEnd + index, coupons.size());
        //調用mybatis批量插入
        batchInsert(coupons.subList(currentPageStart, currentPageEnd));
    }
}
<insert id="batchInsert" parameterType="List">
    insert into dsc_user 
    (
        user_name, nick_name, mobile
)
    values
    <foreach collection='list' item='item' index='index' separator=','>
        (
            #{item.userName,jdbcType=VARCHAR},#{item.nickName,jdbcType=VARCHAR},#{item.mobile,jdbcType=VARCHAR}
        )
    </foreach>
</insert>

 

你們在作批量插入時只須要將最後這塊代碼複製過去就能夠啦

注:mybatis-plus中批量插入方法就是 for循環單條插入;

 

 

以上就是批量導入兩個場景中的解決方案,今天就寫到這裏,再見啦!

 

 

 

昔我往矣,楊柳依依

今我來思,雨雪霏霏

【白話譯文】

回想當初出征時,楊柳依依隨風吹;現在回來路途中,大雪紛紛滿天飛

相關文章
相關標籤/搜索