現在、javaを使用して大きなファイルをMySQL 5.5データベースに保存しようとしています。私のメインクラスはFileDatabaseTestです。これは、次の方法があります。JavaのBufferedInputStreamを使用して大きなファイルをMySQLデータベースに保存するときにjava.lang.outOfMemoryErrorを取得する
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」の表を、そしてそれは、次の列があります。
ID - AUTOINCREMENT, PRIMARY KEY
FILENAME - VARCHAR(100)
FILESIZE - BIGINT
FILEDESCRIPTION - VARCHAR(500)
FILEDATA - LONGBLOB
小さなドキュメントをアップロードすると、プログラムが正常に動作しているが、私は20メガバイトのようなファイルをアップロードすると、アップロード処理が非常に遅いです。だから私は、次のコードでBufferedInputStreamを内部でのFileInputStreamを入れてみました:
stmt.setBinaryStream(4, new BufferedInputStream(new FileInputStream(file));
アップロードプロセスは非常に高速になりました。そのファイルを別のディレクトリにコピーするのが好きです。私はより多くの400メガバイト以上のファイルをアップロードしようとしたときしかし、私は次のエラーを得た:
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 connector/Jのバグですか?または私のコードに何か問題がありますか?
私がここで達成しようとしているのは、Javaヒープスペースを増やさずに、大きなファイル(最大2GB)をMySQLサーバーにアップロードできることです。
Mysql jdbcドライバには、maxAllowedPacketというオプションがあります。このオプションは、デフォルトでmax_allowed_packetの値と一致します。したがって、ドライバがパケット全体に十分なバッファスペースを内部的に割り当てるように思えます。 – Vadim
"maxAllowedPacket"プロパティを変更しようとしましたが、小さい値に変更すると、 "maxAllowedProperty"の値よりも大きいファイルを送信するとエラーが発生します。大きな値を変更すると、大きなファイルをアップロードするときにjava.lang.outOfMemoryエラーが発生します。私が見たところでは、MySQLではSQL文を実行する前にjavaがファイル全体の内容をメモリに読み込んでおり、大きなファイルをアップロードするときにoutOfMemoryエラーが発生すると考えられます。 MySQLがメモリにファイル全体をロードしてからMySQLに送信するのを防ぐ方法はありますか? – Esjee
問題を解決しましたか? – Rafaesp