我目前正在尝试使用 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”表,它有以下列。
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)
所以我尝试使用嵌入式 Apache-Derby 数据库而不是 MySQL,但没有收到错误。我能够使用 BufferedInputStream 在 Derby 数据库中上传 500MB 到 1.5G 的文件。我还观察到,在 MySQL 服务器上使用 BufferedInputStream 上传大文件时,JVM 正在消耗大量内存,而当我在 Derby 数据库中使用它时,JVM 的内存使用量保持在 85MB 到 100MB 左右。
我对 MySQL 比较陌生,我只是使用它的默认配置。我在其配置中唯一更改的是“max_allowed_packet”大小,因此我最多可以将 2GB 文件上传到数据库。所以我想知道错误来自哪里。它是 MySQL 的错误还是 MySQL 连接器/J 的错误?还是我的代码有问题?
我在这里想要实现的是能够使用 java 将大文件(最大 2GB)上传到 MySQL 服务器,而不会增加 java 堆空间。