1

hsqldb 데이터베이스에 파일을 저장하려고하는 간단한 Java 코드를 작성했습니다. 모든 작업은 특정 디렉토리의 파일을 읽고 DB에 저장하는 것입니다. 그것은 단일 스레드이지만 나중에 다중 스레드 액세스에 대처할 수 있도록하기 위해 아파치 commons.dbcp에서 풀링 된 연결을 사용하고 있습니다.commons.dbcp에서 풀링 된 연결을 사용하여 다음과 같은 간단한 Java 코드가 차단되는 이유는 무엇입니까?

문제는 코드가 몇 개의 파일을 읽은 후에 차단된다는 것입니다.

전체 소스 코드를 아래에서 찾으십시오.

는 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(); 
    } 
    } 
} 

코드에 따라 평민 - DBCP 1.6 HSQLDB 2.2.9

공유지 풀, 1.4 그것을 프로젝트 디렉토리 자체에서 실행하면 62 개의 파일을 DB에 저장해야합니다. 위에서 언급 한 두 가지 소스 파일보다 파일이 더 낫다.), 각 파일에 대한 줄을 출력한다.

불행하게도, 그것은 다음과 같은 스택 추적과 여덟 번째 파일에 블록 :

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) 

내가 잘못 뭐하는 거지?

답변

3

당신은 요구하고있다 : 당신의 풋 (문자열,의 InputStream) 방법

m_dataSource.getConnection() 

합니다. 이렇게하면 절대로 닫을 수없는 새로운 연결이 만들어집니다.

어떤 단계에서 62 개의 파일을 넣을 때 풀의 최대 연결 수를 초과하면 풀은 연결이 풀로 반환 될 때까지 대기합니다.

당신과 같은 당신의 방법을 수정하는 경우

: 당신이 풀을 통해 연결에 액세스 할 때

public void put(String name, InputStream data) throws SQLException, IOException { 
    Connection con = null; 
    PreparedStatement set = null; 
    try { 
     con = m_dataSource.getConnection(); 
     set.prepareStatement(SET_SQL); 
     set.setString(1, name); 
     set.setBinaryStream(2, data); 
     set.executeUpdate(); 
    } finally { 
     if (set != null) { 
     set.close(); 
     } 
     if (con != null) { 
     con.close(); 
     } 
    } 
    } 

참고, 당신은 여전히 ​​가까운 호출해야합니다. 이것은 실제로 연결을 닫지는 않지만 풀로 리턴합니다.

+0

나는 바보 야. 고맙습니다. – mark