hsqldbデータベースにファイルを保存しようとする単純なJavaコードを作成しました。特定のディレクトリからファイルを読み取り、それらをDBに配置するだけです。シングルスレッドですが、後でマルチスレッドアクセスに対応できるようにするために、apachecommons.dbcpからのプールされた接続を使用しています。
問題は、いくつかのファイルを読み取った後にコードがブロックされることです。
以下にソースコード全体を見つけてください。
Program.java
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.apache.commons.dbcp.ConnectionFactory;
import org.apache.commons.dbcp.DriverManagerConnectionFactory;
import org.apache.commons.dbcp.PoolableConnectionFactory;
import org.apache.commons.dbcp.PoolingDataSource;
import org.apache.commons.pool.KeyedObjectPoolFactory;
import org.apache.commons.pool.impl.GenericKeyedObjectPoolFactory;
import org.apache.commons.pool.impl.GenericObjectPool;
public class Program {
public static DataSource getPoolingDataSource(String driverClass, String url, String user, String password) throws ClassNotFoundException {
Class.forName(driverClass);
ConnectionFactory connectionFactory = new DriverManagerConnectionFactory(url, user, password);
GenericObjectPool connectionPool = new GenericObjectPool();
KeyedObjectPoolFactory stmtPool = new GenericKeyedObjectPoolFactory(null);
new PoolableConnectionFactory(connectionFactory, connectionPool, stmtPool, null, false, true);
return new PoolingDataSource(connectionPool);
}
public static void main(String[] args) throws ClassNotFoundException, SQLException, IOException, InterruptedException {
String root = args.length == 0 ? "c:/Work/java/ntxdb" : args[0];
Runtime run = Runtime.getRuntime();
Process pr = run.exec("cmd /c del /s/q c:\\tmp\\file.db*");
pr.waitFor();
DataSource ds = getPoolingDataSource("org.hsqldb.jdbcDriver", "jdbc:hsqldb:file:c:/tmp/file.db", "sa", "");
HsqldbFileStorage fs = new HsqldbFileStorage(ds);
putFiles(fs, new File(root));
}
private static void putFiles(HsqldbFileStorage fs, File parent) throws IOException, SQLException {
for (File child : parent.listFiles()) {
if (child.isDirectory()) {
putFiles(fs, child);
} else {
System.out.println(child.getCanonicalPath());
fs.put(child);
}
}
}
}
HsqldbFileStorage.java
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import javax.sql.DataSource;
public class HsqldbFileStorage {
private static final String SET_SQL = "MERGE INTO test" +
" USING (VALUES ?, CAST(? AS BLOB)) I (name, data)" +
" ON (test.name=I.name)" +
" WHEN MATCHED THEN UPDATE SET test.data = I.data" +
" WHEN NOT MATCHED THEN INSERT (name, data) VALUES (I.name, I.data)";
private DataSource m_dataSource;
public HsqldbFileStorage(DataSource dataSource) throws SQLException {
super();
m_dataSource = dataSource;
Connection c = dataSource.getConnection();
c.createStatement().execute("Create Cached Table IF NOT EXISTS test (name VARCHAR(256), data BLOB(10M));");
}
public void put(File file) throws IOException, SQLException {
put(file.getCanonicalPath(), file);
}
public void put(String name, File file) throws IOException, SQLException {
InputStream is = new BufferedInputStream(new FileInputStream(file));
try {
put(name, is);
} finally {
is.close();
}
}
public void put(String name, InputStream data) throws SQLException, IOException {
PreparedStatement set = m_dataSource.getConnection().prepareStatement(SET_SQL);
try {
set.setString(1, name);
set.setBinaryStream(2, data);
set.executeUpdate();
} finally {
set.close();
}
}
}
コードはcommons-dbcp1.4、commons-pool 1.6、hsqldb2.2.9に依存します
プロジェクトディレクトリ自体で実行すると、DBに62個のファイルが配置され(前述の2つのソースファイルよりもはるかに多くのファイルがあります)、ファイルごとに1行が出力されます。
残念ながら、次のスタックトレースで8番目のファイルをブロックします。
at java.lang.Object.wait(Object.java:-1)
at java.lang.Object.wait(Object.java:485)
at org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:1118)
at org.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:106)
at HsqldbFileStorage.put(HsqldbFileStorage.java:41)
at HsqldbFileStorage.put(HsqldbFileStorage.java:34)
at HsqldbFileStorage.put(HsqldbFileStorage.java:28)
at Program.putFiles(Program.java:42)
at Program.putFiles(Program.java:39)
at Program.putFiles(Program.java:39)
at Program.main(Program.java:33)
私は何が間違っているのですか?