MySQL,从解析文件加载数据的最有效方法

时间:2012-10-09 15:20:16

标签: java mysql csv load-data-infile

我的文件格式如下:

Table1; Info
rec_x11;rec_x21;rec_x31;rec_x41
rec_x12;rec_x22;rec_x32;rec_x42
...
\n
Table2; Info
rec_x11;rec_x21;rec_x31;rec_x41
rec_x12;rec_x22;rec_x32;rec_x42
...
\n
Table3; Info
rec_x11;rec_x21;rec_x31;rec_x41
rec_x12;rec_x22;rec_x32;rec_x42
...

从TableX标题之后的下一行开始并以空行分隔符结束的每批记录大约为700-800行。

需要将每批此类行(rec_xyz ...)导入批次标题中指示的相关 MyISAM 表名称(TableX)< / p>

我熟悉使用shell命令将流传递到LOAD DATA命令的选项。

我对简单的java snipet代码很感兴趣,它会解析这个文件并且每次为一批记录执行LOAD DATA(在for循环中并且可能使用seek命令)。

现在我正在尝试使用IGNORE LINES跳过已处理的记录,但如果有一个选项可以忽略来自BELOW的行,我不熟悉吗?

是否有更有效的方法来解析并将此类文件加载到DB中?

修改

我已经读过JDBC从5.1.3开始支持到LOAD DATA的输入流,我可以用它来用输入流迭代文件并每次更改LOAD DATA语句吗?

1 个答案:

答案 0 :(得分:1)

我将我的代码作为解决方案附加,

此解决方案基于MySQL Connector / J 5.1.3及更高版本添加的additional functionalitysetLocalInfileInputStream)。

我将输入流管道插入LOAD DATA INTO语句,而不是使用直接文件URL。

其他信息:我使用BoneCP作为连接池

public final void readFile(final String path)
        throws IOException, SQLException, InterruptedException {
    File file = new File(path);

    final Connection connection = getSqlDataSource().getConnection();
    Statement statement = SqlDataSource.getInternalStatement(connection.createStatement());

    try{
        Scanner fileScanner = new Scanner(file);
        fileScanner.useDelimiter(Pattern.compile("^$", Pattern.MULTILINE));

        while(fileScanner.hasNext()){
            String line;
            while ((line = fileScanner.nextLine()).isEmpty());

            InputStream is = new ByteArrayInputStream(fileScanner.next().getBytes("UTF-8"));
            String [] tableName = line.split(getSeparator());
            setTable((tableName[0]+"_"+tableName[1]).replace('-', '_'));

            String sql = "LOAD DATA LOCAL INFILE '" + SingleCsvImportBean.getOsDependantFileName(file) + "' " 
                    + "INTO TABLE " + SqlUtils.escape(getTable()) 
                    + "FIELDS TERMINATED BY '" + getSeparator() 
                    + "' ESCAPED BY '' LINES TERMINATED BY '" + getLinefeed() + "' ";
            sql += "(" + implodeStringArray(getFields(), ", ") + ")";       
            sql += getSetClause();

            ((com.mysql.jdbc.Statement) statement).setLocalInfileInputStream(is);
            statement.execute(sql);         
        }
    }finally{
        statement.close();
        connection.close();
    }   
}