0

私は現在、Java を使用して MySQL 5.5 データベースに大きなファイルを格納する実験を行っています。私のメイン クラスは FileDatabaseTest と呼ばれます。次のメソッドがあります。

import java.sql.*;
import java.io.*;

...

public class FileDatabaseTest {

...

private void uploadToDatabase(File file, String description) {
        try {
            PreparedStatement stmt = connection.prepareStatement(
                "INSERT INTO FILES (FILENAME, FILESIZE, FILEDESCRIPTION, FILEDATA) " +
                    "VALUES (?, ?, ?, ?)");
            stmt.setString(1, file.getName());
            stmt.setLong(2, file.length());
            stmt.setString(3, description);
            stmt.setBinaryStream(4, new FileInputStream(file));
            stmt.executeUpdate();
            updateFileList();
            stmt.close();
        } catch(SQLException e) {
            e.printStackTrace();
        } catch(FileNotFoundException e) {//thrown by FileInputStream constructor
            e.printStackTrace();
        } catch(SecurityException e) { //thrown by FileInputStream constructor
            e.printStackTrace();
        }
    }

...

}

データベースには「FILES」テーブルという 1 つのテーブルしかなく、次の列があります。

ID - AUTOINCREMENT, PRIMARY KEY

FILENAME - VARCHAR(100)

FILESIZE - BIGINT

FILEDESCRIPTION - VARCHAR(500)

FILEDATA - LONGBLOB

小さなドキュメントをアップロードするときはプログラムは正常に動作しますが、20MB などのファイルをアップロードすると、アップロード プロセスが非常に遅くなります。そこで、次のコードで FileInputStream を BufferedInputStream の中に入れてみました。

stmt.setBinaryStream(4, new BufferedInputStream(new FileInputStream(file));

アップロードプロセスが非常に高速になりました。ファイルを別のディレクトリにコピーするようなものです。しかし、400MB を超えるファイルをアップロードしようとすると、次のエラーが発生しました。

Exception in thread "Thread-5" java.lang.OutOfMemoryError: Java heap space
    at com.mysql.jdbc.Buffer.ensureCapacity(Buffer.java:156)
    at com.mysql.jdbc.Buffer.writeBytesNoNull(Buffer.java:514)
    at com.mysql.jdbc.PreparedStatement.escapeblockFast(PreparedStatement.java:1169)
    at com.mysql.jdbc.PreparedStatement.streamToBytes(PreparedStatement.java:5064)
    at com.mysql.jdbc.PreparedStatement.fillSendPacket(PreparedStatement.java:2560)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2401)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2345)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2330)
    at FileDatabaseTest$2.run(FileDatabaseTest.java:312)
    at java.lang.Thread.run(Thread.java:662)

そのため、MySQL の代わりに組み込みの Apache-Derby データベースを使用してみましたが、エラーは発生しませんでした。BufferedInputStream を使用して、Derby データベースに 500MB から 1.5G のファイルをアップロードできました。また、大きなファイルをアップロードする際に MySQL サーバーで BufferedInputStream を使用すると、JVM が大量のメモリを消費しているのに対し、Derby データベースで使用すると、JVM のメモリ使用量は約 85MB から 100MB に維持されることがわかりました。

私は MySQL に比較的慣れていないため、デフォルトの構成を使用しています。構成で変更したのは「max_allowed_pa​​cket」サイズだけで、最大 2GB のファイルをデータベースにアップロードできます。だから私はエラーがどこから来たのだろうか。MySQL または MySQL コネクタ/J のバグですか? または私のコードに何か問題がありますか?

ここで達成しようとしているのは、Java ヒープ スペースを増やすことなく、Java を使用して大きなファイル (最大 2GB) を MySQL サーバーにアップロードできるようにすることです。

4

4 に答える 4

1

JVM ヒープ サイズを増やしたくない場合は、別の解決方法があります。

まず、MySQL のバージョンが 5.0 より新しい必要があります。

次に、Statement.getResultSetType() を TYPE_FORWARD_ONLY にし、ResultSetConcurrency を CONCUR_READ_ONLY (デフォルト) にする必要があります。

3 番目に、次のいずれかの行を含めます。 1).statement.setFetchSize(Integer.MIN_VALUE); 2).((com.mysql.jdbc.Statement)stat).enableStreamingResults();

これで、結果行を 1 つずつフェッチします

于 2013-05-16T10:06:28.723 に答える
0

MySQL JDBCの問題のようです。もちろん、GZip + Piped I/O を検討することもできます。

また、挿入を部分的に行うというひどい解決策も見つけました。

UPDATE FILES SET FILEDATA = CONCAT(FILEDATA, ?)

大きなファイルの場合は、ディスクに保存する方がよいと結論付けることができます。

それにもかかわらず:

final int SIZE = 1024*128;
InputStream in = new BufferedInputStream(new FileInputStream(file), SIZE);
stmt.setBinaryStream(4, in);
stmt.executeUpdate();
updateFileList();
stmt.close();
in.close(); //?

デフォルトのバッファ サイズは 8 KB だと思います。バッファが大きいとメモリの動作が異なる可能性があり、問題が明らかになる可能性があります。

自分を閉じても、試してみても問題ありません。

于 2013-05-16T10:18:15.830 に答える
0

Java コードを実行するときの JVM ヒープ サイズの増加:

right click your java file
    ->run as->run configurations->arguments->VM arguments
于 2012-03-07T10:06:27.630 に答える
0

念のため、JVM ヒープ サイズを増やしてみてください。

Javaヒープサイズを永久に増やしますか? http://javahowto.blogspot.com/2006/06/6-common-errors-in-setting-java-heap.html

于 2012-01-24T03:42:14.467 に答える