MySQL使用load data local infile 從文件中導入數據比insert語句要快,MySQL文檔上說要快20倍左右。
但是這個方法有個缺點,就是導入數據之前,必須要有文件,也就是說從文件中導入。這樣就需要去寫文件,
以及文件刪除等維護。某些情況下,比如數據源併發的話,還會出現寫文件併發問題,很難處理。
那麼有沒有什麼辦法,可以達到同樣的效率,直接從內存(IO流中)中導入數據,而不需要寫文件呢?
前段時間,去MySQL社區的時候發現了這樣一個方法:setLocalInfileInputStream(),此方法位於com.mysql.jdbc.PreparedStatement 類中
前段時間,去MySQL社區的時候發現了這樣一個方法:setLocalInfileInputStream(),此方法位於com.mysql.jdbc.PreparedStatement 類中
下面是具體實現:
通過使用 MySQL JDBC 的setLocalInfileInputStream 方法實現從Java InputStream中load data local infile 到MySQL數據庫中。
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 DEFAULT CHARSET=utf8
Java代碼如下:
package com.seven.dbTools.DBTools;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
import org.apache.log4j.Logger;
/**
* @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);
}
}
提示:
String testSql ="LOAD DATA LOCAL INFILE 'sql.csv' IGNORE INTO TABLE test.test (a,b,c,d,e,f)";
使用setLocalInfileInputStream方法,會直接忽略掉文件名稱,而直接將IO流導入到數據庫中。
參考:
http://assets.en.oreilly.com/1/event/21/Connector_J%20Performance%20Gems%20Presentation.pdf
http://jeffrick.com/2010/03/23/bulk-insert-into-a-mysql-database/