Java利用MYSQL LOAD DATA LOCAL INFILE實(shí)現(xiàn)大批量導(dǎo)入數(shù)據(jù)到MySQL
Mysql load data的使用
數(shù)據(jù)庫(kù)中,最常見(jiàn)的寫(xiě)入數(shù)據(jù)方式是通過(guò)SQL INSERT來(lái)寫(xiě)入,另外就是通過(guò)備份文件恢復(fù)數(shù)據(jù)庫(kù),這種備份文件在MySQL中是SQL腳本,實(shí)際上執(zhí)行的還是在批量INSERT語(yǔ)句。
在實(shí)際中,常常會(huì)遇到兩類(lèi)問(wèn)題:一類(lèi)是數(shù)據(jù)導(dǎo)入,比如從word、excel表格或者txt文檔導(dǎo)入數(shù)據(jù)(這些數(shù)據(jù)一般來(lái)自于非技術(shù)人員通過(guò)OFFICE工具錄入的文檔);一類(lèi)數(shù)據(jù)交換,比如從MySQL、Oracle、DB2數(shù)據(jù)庫(kù)之間的數(shù)據(jù)交換。
這其中就面臨一個(gè)問(wèn)題:數(shù)據(jù)庫(kù)SQL腳本有差異,SQL交換比較麻煩。但是幾乎所有的數(shù)據(jù)庫(kù)都支持文本數(shù)據(jù)導(dǎo)入(LOAD)導(dǎo)出(EXPORT)功能。利用這一點(diǎn),就可以解決上面所提到的數(shù)據(jù)交換和導(dǎo)入問(wèn)題。
MySQL的LOAD DATAINFILE語(yǔ)句用于高速地從一個(gè)文本文件中讀取行,并裝入一個(gè)表中。文件名稱(chēng)必須為一個(gè)文字字符串。下面以MySQL5為例說(shuō)明,說(shuō)明如何使用MySQL的LOADDATA命令實(shí)現(xiàn)文本數(shù)據(jù)的導(dǎo)入。
注意:這里所說(shuō)的文本是有一定格式的文本,比如說(shuō),文本分行,每行中用相同的符號(hào)隔開(kāi)文本等等。等等,獲取這樣的文本方法也非常的多,比如可以把word、excel表格保存成文本,或者是一個(gè)csv文件。
在項(xiàng)目中,使用的環(huán)境是快速上傳一個(gè)csv文件,原系統(tǒng)中是使用的db2數(shù)據(jù)庫(kù),然后調(diào)用了與mysql的loaddata相似的一個(gè)函數(shù)sysproc.db2load。但是loaddata在mysql的存儲(chǔ)過(guò)程是不能使用的。采取的方法時(shí)在java代碼中調(diào)用此方法。
實(shí)現(xiàn)的例子:
準(zhǔn)備測(cè)試表
SQL如下:
USE test; CREATE TABLE `test` ( `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, `a` int(11) NOT NULL, `b` bigint(20) UNSIGNED NOT NULL, `c` bigint(20) UNSIGNED NOT NULL, `d` int(10) UNSIGNED NOT NULL, `e` int(10) UNSIGNED NOT NULL, `f` int(10) UNSIGNED NOT NULL, PRIMARY KEY (`id`), KEY `a_b` (`a`, `b`) ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARSET = utf8
Java代碼如下:
package com.seven.dbTools.DBTools;
import org.apache.log4j.Logger;
import org.springframework.jdbc.core.JdbcTemplate;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import javax.sql.DataSource;
/**
*
@author seven
*
@since 07.03.2013
*/
public class BulkLoadData2MySQL {
private static final Logger logger = Logger.getLogger(BulkLoadData2MySQL.class);
private JdbcTemplate jdbcTemplate;
private Connection conn = null;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public static InputStream getTestDataInputStream() {
StringBuilder builder = new StringBuilder();
for (int i = 1; i <= 10; i++) {
for (int j = 0; j <= 10000; j++) {
builder.append(4);
builder.append("\t");
builder.append(4 + 1);
builder.append("\t");
builder.append(4 + 2);
builder.append("\t");
builder.append(4 + 3);
builder.append("\t");
builder.append(4 + 4);
builder.append("\t");
builder.append(4 + 5);
builder.append("\n");
}
}
byte[] bytes = builder.toString().getBytes();
InputStream is = new ByteArrayInputStream(bytes);
return is;
}
/**
*
* load bulk data from InputStream to MySQL
*/
public int bulkLoadFromInputStream(String loadDataSql,
InputStream dataStream) throws SQLException {
if (dataStream == null) {
logger.info("InputStream is null ,No data is imported");
return 0;
}
conn = jdbcTemplate.getDataSource().getConnection();
PreparedStatement statement = conn.prepareStatement(loadDataSql);
int result = 0;
if (statement.isWrapperFor(com.mysql.jdbc.Statement.class)) {
com.mysql.jdbc.PreparedStatement mysqlStatement = statement.unwrap(com.mysql.jdbc.PreparedStatement.class);
mysqlStatement.setLocalInfileInputStream(dataStream);
result = mysqlStatement.executeUpdate();
}
return result;
}
public static void main(String[] args) {
String testSql = "LOAD DATA LOCAL INFILE 'sql.csv' IGNORE INTO TABLE test.test (a,b,c,d,e,f)";
InputStream dataStream = getTestDataInputStream();
BulkLoadData2MySQL dao = new BulkLoadData2MySQL();
try {
long beginTime = System.currentTimeMillis();
int rows = dao.bulkLoadFromInputStream(testSql, dataStream);
long endTime = System.currentTimeMillis();
logger.info("importing " + rows +
" rows data into mysql and cost " + (endTime - beginTime) +
" ms!");
} catch (SQLException e) {
e.printStackTrace();
}
System.exit(1);
}
}
提示:
例子中的代碼使用setLocalInfileInputStream方法,會(huì)直接忽略掉文件名稱(chēng),而直接將IO流導(dǎo)入到數(shù)據(jù)庫(kù)中。在實(shí)際的實(shí)現(xiàn)中也可以把文件上傳到服務(wù)器,然后讀文件再導(dǎo)入文件,此時(shí)load data的local參數(shù)應(yīng)該去掉,并且文件名應(yīng)該是完整的絕對(duì)路徑的名字。
最后附上LOAD DATA INFILE語(yǔ)法
LOAD DATA [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE 'file_name.txt' [REPLACE | IGNORE] INTO TABLE tbl_name [FIELDS [TERMINATED BY 'string'] [[OPTIONALLY] ENCLOSED BY 'char'] [ESCAPED BY 'char' ] ] [LINES [STARTING BY 'string'] [TERMINATED BY 'string'] ] [IGNORE number LINES] [(col_name_or_user_var,...)] [SET col_name = expr,...]]
總結(jié)
LOADDATA是一個(gè)很有用的命令,從文件中導(dǎo)入數(shù)據(jù)比insert語(yǔ)句要快,MySQL文檔上說(shuō)要快20倍左右。但是命令的選項(xiàng)很多,然而大多都用不到,如果真的需要,用的時(shí)候看看官方文檔即可。
相關(guān)文章
Java設(shè)計(jì)模式之橋接模式實(shí)例詳解
這篇文章主要介紹了Java設(shè)計(jì)模式之橋接模式,結(jié)合實(shí)例形式詳細(xì)分析了橋接模式的概念、功能、Java實(shí)現(xiàn)方法及相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-09-09
Java實(shí)現(xiàn)FTP文件的上傳和下載功能的實(shí)例代碼
FTP 是File Transfer Protocol(文件傳輸協(xié)議)的英文簡(jiǎn)稱(chēng),而中文簡(jiǎn)稱(chēng)為“文傳協(xié)議”。接下來(lái)通過(guò)本文給大家實(shí)例講解Java實(shí)現(xiàn)FTP文件的上傳和下載功能,需要的的朋友一起看看吧2016-11-11
SpringMVC項(xiàng)目訪問(wèn)controller時(shí)候報(bào)404的解決
這篇文章主要介紹了SpringMVC項(xiàng)目訪問(wèn)controller時(shí)候報(bào)404的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
springboot 啟動(dòng)時(shí)初始化數(shù)據(jù)庫(kù)的步驟
這篇文章主要介紹了springboot 啟動(dòng)時(shí)初始化數(shù)據(jù)庫(kù)的步驟,幫助大家更好的理解和使用springboot框架,感興趣的朋友可以了解下2021-01-01
Java文件操作工具類(lèi)fileUtil實(shí)例【文件增刪改,復(fù)制等】
這篇文章主要介紹了Java文件操作工具類(lèi)fileUtil,結(jié)合實(shí)例形式分析了java針對(duì)文件進(jìn)行讀取、增加、刪除、修改、復(fù)制等操作的相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2017-10-10
淺析如何在Java應(yīng)用中優(yōu)雅的發(fā)送短信
很多業(yè)務(wù)場(chǎng)景里,我們都需要發(fā)送短信,比如登陸驗(yàn)證碼、告警、營(yíng)銷(xiāo)通知、節(jié)日祝福等等,這篇文章,我們聊聊 Java 應(yīng)用中如何優(yōu)雅的發(fā)送短信,文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下2023-11-11
快速解決跨域請(qǐng)求問(wèn)題:jsonp和CORS
這篇文章主要介紹了快速解決跨域請(qǐng)求問(wèn)題:jsonp和CORS,涉及jsonp和CORS的介紹,分享了前端 jQuery 寫(xiě)法,后端 SpringMVC 配置,后端非 SpringMVC 配置等相關(guān)內(nèi)容,具有一定借鑒價(jià)值,需要的朋友可以參考下。2017-11-11
使用springboot結(jié)合vue實(shí)現(xiàn)sso單點(diǎn)登錄
這篇文章主要為大家詳細(xì)介紹了如何使用springboot+vue實(shí)現(xiàn)sso單點(diǎn)登錄,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-06-06

