2010-04-26 2 views
7

저는 여전히 파트 타임으로 일하는 학부생입니다. 그래서 나는 항상 일을하는 더 좋은 방법을 알고 자 노력하고 있습니다. 최근에 나는 프로그램의 메인 쓰레드가 어떤 작업을 수행하고 그것이 끝났다고 말하는 레코드를 업데이트 할 "작업"쓰레드 (각 db "작업"레코드)를 생성하는 작업을위한 프로그램을 작성해야했다. 따라서 데이터베이스 연결 개체와 PreparedStatement 개체가 필요하거나 ThreadedTask 개체에서 사용할 수 있습니다.자바 쓰레드의 PreparedStatements 사용이 맞습니까?

이것은 대략 작성한 것으로, 스레드 당 PreparedStatement 개의 오브젝트를 낭비하고 있습니까? 나는

이 스레드 안전한가요 ..

 
Thread A stmt.setInt(); 
Thread B stmt.setInt(); 
Thread A stmt.execute(); 
Thread B stmt.execute(); 

A's 버전 execed 결코 극복 ... 경쟁 조건을 만들 수 PreparedStatments 정적을 생각? 항상 똑같은 거대한 쓰레기가 아니라는 것을 PreparedStatement 개체를 만들고 파괴하고 있습니까?

public class ThreadedTask implements runnable { 
    private final PreparedStatement taskCompleteStmt; 

    public ThreadedTask() { 
     //... 
     taskCompleteStmt = Main.db.prepareStatement(...); 
    } 

    public run() { 
     //... 
     taskCompleteStmt.executeUpdate(); 
    } 
} 

public class Main { 
    public static final db = DriverManager.getConnection(...); 
} 
+2

연결을 저장하지 마십시오. 필요할 때 연결을 설정하십시오. bettr 성능이 필요한 경우 연결 풀을 사용하십시오. Thilo가 아래에 말했듯이 스레드간에 물건을 공유하지 마십시오. –

답변

16

나는 스레드 간의 데이터베이스 연결 (및 준비된 명령문)을 공유하는 것이 좋지 않다고 생각합니다. JDBC는 thread-safe 연결을 필요로하지 않으며, 대부분의 드라이버가 아닌 것으로 기대합니다.

모든 스레드에게 자체 연결을 제공합니다 (또는 모든 쿼리에 대해 연결을 동기화하지만 다중 스레드를 갖는 목적을 상실했을 수 있음).

항상 똑같은 엄청난 낭비가없는 PreparedStatement 객체를 만들고 파괴하고 있습니까?

아니요. 대부분의 작업은 서버에서 발생하며 동일한 SQL 문을 사용하는 경우 캐시되고 다시 사용됩니다. 일부 JDBC 드라이버는 명령문 캐싱을 지원하므로 클라이언트 측 명령문 핸들조차도 재사용 할 수 있습니다.

여러 스레드 대신 (또는 그에 추가하여) 일괄 처리 된 쿼리를 사용하여 상당한 향상을 볼 수 있습니다. 쿼리를 한 번 준비하고 단일 큰 배치의 많은 데이터에 대해 실행합니다.

3

연결 풀을 사용하고 각 스레드가 풀에서 연결을 요청하도록하는 것이 가장 좋습니다. 전달 된 연결에 대한 명령문을 작성하고 닫은 것을 기억하고 완료되면 다시 풀에 놓습니다. 풀을 사용하면 스레드 동시성이 문제가되는 것을 발견하면 사용 가능한 연결 수를 쉽게 늘릴 수 있다는 이점이 있습니다.

6

threadsafety는 여기에서 문제가되지 않습니다. 모두 문법적으로나 기능적으로 잘 보입니다. 약 30 분 동안 작동해야합니다. 그러나 리소스 누출 문제가 여기에 있습니다. 사용 후 약 30 분 후에 응용 프로그램이 닫히지 않으므로 응용 프로그램이 충돌합니다. 데이터베이스는 조만간 조만간 연결을 닫아이를 다시 청구 할 수 있습니다.

즉, preparedstatement의 캐싱에 대해 걱정할 필요가 없습니다. JDBC 드라이버와 DB가이 작업을 처리합니다. 리소스 누수에 대해 걱정하지 말고 JDBC 코드를 최대한 확고하게 만드십시오.

public class ThreadedTask implements runnable { 
    public run() { 
     Connection connection = null; 
     Statement statement = null; 
     try { 
      connection = DriverManager.getConnection(url); 
      statement = connection.prepareStatement(sql); 
      // ... 
     } catch (SQLException e) { 
      // Handle? 
     } finally { 
      if (statement != null) try { statement.close(); } catch (SQLException logOrIgnore) {} 
      if (connection != null) try { connection.close(); } catch (SQLException logOrIgnore) {} 
     } 
    } 
} 

는 당신이 JDBC 코드를 작성하는 방법을 방법을 변경할 수 있습니다 것을 의미하지 않는다 그런데 c3p0 (이 같은 연결 풀을 활용, 성능을 연결 향상시키기 위해, 항상 을 획득하고이의 자원을 닫습니다 가능한 가장 짧은 범위try-finally 블록).

+1

Apache Commons DBUtils에서 모든 try/catch를 처리하는 경량 래퍼를 살펴보십시오. – Thilo

+0

JPA를 사용할 수도 있습니다. 더 편리하지 않을 수 있습니다. – BalusC

+0

Java 7 이상을 사용하는 경우 : "자원 블록 사용"을 선호하십시오. 이 경우 연결 및 문을 닫는 것을 잊지 못할 수 있습니다. –

관련 문제