私は現在、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_packet」サイズだけで、最大 2GB のファイルをデータベースにアップロードできます。だから私はエラーがどこから来たのだろうか。MySQL または MySQL コネクタ/J のバグですか? または私のコードに何か問題がありますか?
ここで達成しようとしているのは、Java ヒープ スペースを増やすことなく、Java を使用して大きなファイル (最大 2GB) を MySQL サーバーにアップロードできるようにすることです。