JDBC에서 연결 풀을 설정하는 방법은 무엇입니까?


111

누구든지 JDBC 연결 풀을 설정하는 방법에 대한 예제 나 링크를 제공 할 수 있습니까?

Google 검색에서 나는 이것을하는 많은 다른 방법을 보았고 다소 혼란 스럽습니다.

궁극적으로 java.sql.Connection객체 를 반환하려면 코드가 필요 하지만 시작하는 데 문제가 있습니다. 어떤 제안이라도 환영합니다.

업데이트 : 합니까하지 javax.sql또는 java.sql풀 된 접속의 구현이? 이것을 사용하는 것이 왜 최선이 아닐까요?


8
아니오, 재고 JDBC는 연결 풀링을 제공하지 않습니다. 이를 위해서는 별도의 라이브러리가 필요합니다. 대부분의 앱 서버와 서블릿 컨테이너에는 연결 풀이 포함되어 있습니다. 또한 JPA 구현은 일반적으로 구현도 제공합니다.
Will Hartung

3
현대 자바 사용자를위한 업데이트입니다. JDBC 3.0+ (Java 6에서 사용되는 것으로 생각합니까?)에는 풀링 된 DB 연결에 대한 구현이 있습니다. Java 7은 JDBC 4 및 Java 8 JDBC 4.1을 사용합니다.
BRasmussen

답변:


102

독립형 연결 풀이 필요한 경우 DBCP 보다 C3P0 을 선호합니다 ( 이전 답변 에서 언급 했음). 부하가 심한 경우 DBCP에 너무 많은 문제가 있습니다. C3P0을 사용하는 것은 매우 간단합니다. 로부터 문서 :

ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass( "org.postgresql.Driver" ); //loads the jdbc driver
cpds.setJdbcUrl( "jdbc:postgresql://localhost/testdb" );
cpds.setUser("swaldman");
cpds.setPassword("test-password");

// the settings below are optional -- c3p0 can work with defaults
cpds.setMinPoolSize(5);
cpds.setAcquireIncrement(5);
cpds.setMaxPoolSize(20);

// The DataSource cpds is now a fully configured and usable pooled DataSource 

그러나 응용 프로그램 서버 내부에서 실행하는 경우 제공되는 기본 제공 연결 풀을 사용하는 것이 좋습니다. 이 경우이를 구성하고 (애플리케이션 서버 문서 참조) JNDI를 통해 데이터 소스를 검색해야합니다.

DataSource ds = (DataSource) new InitialContext().lookup("jdbc/myDS");

1
저것도 마찬가지입니다. 나는 수년 동안 부하가 걸리는 DBCP 교착 상태를 관찰하고 있습니다. 버전 이후 버전.
Vasiliy

예,하지만 C3P0도 BoneCP에서 최고의 경험을했습니다
Nicolas Mommaerts

1
BoneCP처럼 보이는이되었습니다 되지 찬성 HikariCP . HikariCP는 아래 답변 에서도 언급 됩니다 .
kaartic

19

일반적으로 연결 풀이 필요한 경우 일부 관리 환경에서 실행되는 응용 프로그램을 작성합니다. 즉, 응용 프로그램 서버 내에서 실행됩니다. 이 경우 다른 옵션을 시도하기 전에 애플리케이션 서버가 제공하는 연결 풀링 기능확인 하십시오 .

즉시 사용 가능한 솔루션은 나머지 애플리케이션 서버 시설과 가장 잘 통합됩니다. 그러나 응용 프로그램 서버 내에서 실행하지 않는 경우 Apache Commons DBCP 구성 요소를 권장합니다 . 널리 사용되며 대부분의 응용 프로그램에 필요한 모든 기본 풀링 기능을 제공합니다.


18

HikariCP

현대적이고 빠르며 간단합니다. 나는 모든 새로운 프로젝트에 그것을 사용합니다. 나는 C3P0보다 많이 선호하고 다른 풀을 너무 잘 모릅니다.


18

바퀴를 재발 명하지 마십시오.

즉시 사용 가능한 타사 구성 요소 중 하나를 사용해보십시오.

  • Apache DBCP- 이것은 Tomcat에서 내부적으로 사용되며 실제로는 사용자가 사용합니다.
  • c3p0

Apache DBCP는 javax.sql.DataSource 풀링을 설정하는 방법에 대한 다른 예제와 함께 제공됩니다 . 다음은 시작하는 데 도움 이되는 하나의 샘플 입니다.


1
C3P0이라고합니다. DBCP는 단일 스레드에 대한 액세스를 잠그기 때문에 다중 스레드 환경에서 DBCP보다 성능이 뛰어납니다.
BalusC

@BalusC. 수정 해주셔서 감사합니다 disclecsia. 링크가 정확하다는 것을 알 수 있습니다. :)
Alexander Pogrebnyak

1
@Mudassir. Spring- > static.springsource.com/projects/tc-server/2.0/admin/htmlsingle/… 에서 Tomcat에 기여한 DBCP의 드롭 인 대체품을 살펴 보는 것이 좋습니다 . 사용하기 위해 전체 Tomcat 서버가 필요하지 않으며 단지 하나의 jar tomcat-jdbc입니다. Maven Central-> org.apache.tomcat:tomcat-jdbc:jar:7.0.22-> search.maven.org/…
Alexander Pogrebnyak

@AlexanderPogrebnyak : 알렉산더에게 감사합니다. Axis 웹 서비스에서 CP를 사용할 계획입니다. 당신의 제안에 대해 생각할 것입니다. – Mudassir 7 분 전
Mudassir

17

commons-dbcp 라이브러리를 사용하는 것이 좋습니다 . 사용 방법에 대한 많은 예가 나열되어 있으며 여기에 간단한 이동 링크가 있습니다. 사용법은 매우 간단합니다.

 BasicDataSource ds = new BasicDataSource();
 ds.setDriverClassName("oracle.jdbc.driver.OracleDriver")
 ds.setUsername("scott");
 ds.setPassword("tiger");
 ds.setUrl(connectURI);
 ...
 Connection conn = ds.getConnection();

데이터 소스는 한 번만 작성하면되므로 작성 방법을 모르는 경우 문서를 읽으십시오. 자원이 누출되지 않도록 JDBC 문을 올바르게 작성하는 방법을 모르는 경우이 Wikipedia 페이지 를 읽어 보는 것도 좋습니다 .


8
이것이 실제로 연결 풀을 생성합니까?
llm

@llm 물론입니다! javax.sql.DataSource인터페이스의 정의는 "연결 풀링"의 구현을 포함 (게다가, 난 당신이 이미 JDBC 인터페이스가 무엇인지 생각).
에디

7

내가 일하는 곳에서 사용하는 앱 서버 (내가 기억하는대로 Oracle Application Server 10g)에서는 풀링이 앱 서버에 의해 처리됩니다. 우리는이 검색 javax.sql.DataSource기호가있는 JNDI 조회를 사용 javax.sql.InitialContext.

이것은 이와 같은 일을했습니다

try {     
   context = new InitialContext();
   jdbcURL = (DataSource) context.lookup("jdbc/CachedDS");
   System.out.println("Obtained Cached Data Source ");
}
catch(NamingException e)   
{  
    System.err.println("Error looking up Data Source from Factory: "+e.getMessage());
}

(우리는이 코드를 작성하지 않았으며이 문서 에서 복사했습니다 .)


5

  • 풀링 메커니즘은 객체를 미리 생성하는 방법입니다. 클래스가로드 될 때.
  • performance[Object-Data에 대한 작업을 수행하기 위해 동일한 객체를 재사용함으로써] 및 memory[많은 객체를 할당 및 할당 해제하면 상당한 메모리 관리 오버 헤드가 발생 함] 응용 프로그램이 향상됩니다 .
  • 동일한 Object를 사용하므로 가비지 수집 부하를 줄이므로 객체 정리가 필요하지 않습니다.

«풀링 [ Object풀, String상수 풀, Thread풀, 연결 풀]

문자열 상수 풀

  • 문자열 리터럴 풀은 각 고유 한 문자열 값의 복사본을 하나만 유지합니다. 불변이어야합니다.
  • 인턴 메서드가 호출되면 equals 메서드를 사용하여 풀에서 동일한 콘텐츠의 객체 가용성을 확인합니다. «Pool에서 String-copy를 사용할 수있는 경우 참조를 반환합니다. «그렇지 않으면 String 개체가 풀에 추가되고 참조를 반환합니다.

예 : 풀에서 고유 개체 를 확인하는 문자열 입니다.

public class StringPoolTest {
    public static void main(String[] args) { // Integer.valueOf(), String.equals()
        String eol = System.getProperty("line.separator"); //java7 System.lineSeparator();

        String s1 = "Yash".intern();
        System.out.format("Val:%s Hash:%s SYS:%s "+eol, s1, s1.hashCode(), System.identityHashCode(s1));
        String s2 = "Yas"+"h".intern();
        System.out.format("Val:%s Hash:%s SYS:%s "+eol, s2, s2.hashCode(), System.identityHashCode(s2));
        String s3 = "Yas".intern()+"h".intern();
        System.out.format("Val:%s Hash:%s SYS:%s "+eol, s3, s3.hashCode(), System.identityHashCode(s3));
        String s4 = "Yas"+"h";
        System.out.format("Val:%s Hash:%s SYS:%s "+eol, s4, s4.hashCode(), System.identityHashCode(s4));
    }
}

유형 4 사용하여 연결 풀 드라이버를 제 3 자 라이브러리를 사용하여 [ DBCP2, c3p0, Tomcat JDBC]

Type 4 - The Thin driver converts JDBC calls directly into the vendor-specific database protocol Ex[Oracle - Thick, MySQL - Quora]. 위키

연결 풀 메커니즘에서 클래스가로드되면 physical JDBC connection개체를 가져와 사용자에게 래핑 된 물리적 연결 개체를 제공합니다. PoolableConnection실제 연결을 감싸는 래퍼입니다.

  • getConnection()연결 개체 풀 에서 무료 래핑 연결 중 하나를 선택 하고 반환합니다.
  • close() 닫는 대신 래핑 된 연결을 풀로 다시 반환합니다.

예 : Java 7 [ try-with-resources] 과 함께 ~ DBCP2 연결 풀 사용

public class ConnectionPool {
    static final BasicDataSource ds_dbcp2 = new BasicDataSource();
    static final ComboPooledDataSource ds_c3p0 = new ComboPooledDataSource();
    static final DataSource ds_JDBC = new DataSource();

    static Properties prop = new Properties();
    static {
        try {
            prop.load(ConnectionPool.class.getClassLoader().getResourceAsStream("connectionpool.properties"));

            ds_dbcp2.setDriverClassName( prop.getProperty("DriverClass") );
            ds_dbcp2.setUrl( prop.getProperty("URL") );
            ds_dbcp2.setUsername( prop.getProperty("UserName") );
            ds_dbcp2.setPassword( prop.getProperty("Password") );
            ds_dbcp2.setInitialSize( 5 );

            ds_c3p0.setDriverClass( prop.getProperty("DriverClass") );
            ds_c3p0.setJdbcUrl( prop.getProperty("URL") );
            ds_c3p0.setUser( prop.getProperty("UserName") );
            ds_c3p0.setPassword( prop.getProperty("Password") );
            ds_c3p0.setMinPoolSize(5);
            ds_c3p0.setAcquireIncrement(5);
            ds_c3p0.setMaxPoolSize(20);

            PoolProperties pool = new PoolProperties();
            pool.setUrl( prop.getProperty("URL") );
            pool.setDriverClassName( prop.getProperty("DriverClass") );
            pool.setUsername( prop.getProperty("UserName") );
            pool.setPassword( prop.getProperty("Password") );
            pool.setValidationQuery("SELECT 1");// SELECT 1(mysql) select 1 from dual(oracle)

            pool.setInitialSize(5);
            pool.setMaxActive(3);
            ds_JDBC.setPoolProperties( pool );
        } catch (IOException e) {   e.printStackTrace();
        } catch (PropertyVetoException e) { e.printStackTrace(); }
    }

    public static Connection getDBCP2Connection() throws SQLException {
        return ds_dbcp2.getConnection();
    }

    public static Connection getc3p0Connection() throws SQLException {
        return ds_c3p0.getConnection();
    }

    public static Connection getJDBCConnection() throws SQLException {
        return ds_JDBC.getConnection();
    }
}
public static boolean exists(String UserName, String Password ) throws SQLException {
    boolean exist = false;
    String SQL_EXIST = "SELECT * FROM users WHERE username=? AND password=?";
    try ( Connection connection = ConnectionPool.getDBCP2Connection();
          PreparedStatement pstmt = connection.prepareStatement(SQL_EXIST); ) {
        pstmt.setString(1, UserName );
        pstmt.setString(2, Password );

        try (ResultSet resultSet = pstmt.executeQuery()) {
            exist = resultSet.next(); // Note that you should not return a ResultSet here.
        }
    }
    System.out.println("User : "+exist);
    return exist;
}

jdbc:<DB>:<drivertype>:<HOST>:<TCP/IP PORT>:<dataBaseName> jdbc:oracle:thin:@localhost:1521:myDBName jdbc:mysql://localhost:3306/myDBName

connectionpool.properties

URL         : jdbc:mysql://localhost:3306/myDBName
DriverClass : com.mysql.jdbc.Driver
UserName    : root
Password    :

응용 프로그램 : 모든 연결이 닫힐 때 연결 문제를 방지하기 위해 [MySQL "wait_timeout"기본 8 시간] 기본 DB와의 연결을 다시 시작합니다.

testOnBorrow = true 및 validationQuery = "SELECT 1"을 설정하여 모든 연결을 테스트 할 수 있으며 더 이상 사용되지 않는 MySQL 서버용 autoReconnect를 사용하지 마십시오. 발행물

===== ===== context.xml ===== =====
<?xml version="1.0" encoding="UTF-8"?>
<!-- The contents of this file will be loaded for a web application -->
<Context>
    <Resource name="jdbc/MyAppDB" auth="Container" 
        factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
        type="javax.sql.DataSource" 

        initialSize="5" minIdle="5" maxActive="15" maxIdle="10"

        testWhileIdle="true"
            timeBetweenEvictionRunsMillis="30000"

        testOnBorrow="true"
            validationQuery="SELECT 1"
            validationInterval="30000"


        driverClassName="com.mysql.jdbc.Driver" 
        url="jdbc:mysql://localhost:3306/myDBName" 
        username="yash" password="777"
    />
</Context>

===== ===== web.xml ===== =====
<resource-ref>
    <description>DB Connection</description>
    <res-ref-name>jdbc/MyAppDB</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref>
===== ===== DBOperations ===== =====
servlet «   init() {}
Normal call used by sevlet  « static {}

static DataSource ds;
static {
    try {
        Context ctx=new InitialContext();
        Context envContext = (Context)ctx.lookup("java:comp/env");
        ds  =   (DataSource) envContext.lookup("jdbc/MyAppDB");
    } catch (NamingException e) {   e.printStackTrace();    }
}

다음을 참조하십시오.


문자열 상수 풀 예제에서 "If String-copy is available [.equals ()] in the Pool은 다음 참조를 반환합니다.«그렇지 않으면 String 개체가 풀에 추가되고 참조를 반환합니다."라고 썼을 때 이해합니다. 그러나 in public class StringPoolTest에는 2 개의 void 메서드가 있으므로 아무것도 반환하지 않습니다. 이 코드는 실제로 문자열 풀을 관리하는 과정을 거치나요? 인수를 사용하지 않는 것 같습니다.
jeffery_the_wind

@jeffery_the_wind :-풀 개념을 아는 것입니다. 문자열 풀 확인을 위해 방금 hashCode, identityHashCode 메서드를 사용 했습니다 . 코드 수정 ...
야쉬

죄송합니다. s1정의되지 않았습니까?
jeffery_the_wind

좋아요, 제가 모든 것을보고 있는지 확인하고 싶었습니다. 나는 그것에 대해 일할 것이다. 당신의 ConnectionPool클래스에 더 가까운 무언가에 필요한 것 . 정말 고마워.
jeffery_the_wind

5

2017 년 말 Proxool, BoneCP, C3P0, DBCP는 현재 대부분 사용되지 않습니다. HikariCP (2012 년에 생성됨)는 유망 해 보이며 내가 아는 다른 모든 것의 문을 날려 버립니다. http://www.baeldung.com/hikaricp

Proxool에는 다음과 같은 여러 가지 문제가 있습니다
.-부하가 높으면 최대 연결 수를 초과하고 최대 이하로 반환되지 않을
수 있습니다 .-연결이 만료 된 후에도 최소 연결로 돌아 가지 않도록 관리
할 수 있습니다.-전체 풀 (및 모든 서버 / 클라이언트 스레드)을 잠글 수 있습니다. HouseKeeper 스레드 중에 데이터베이스에 연결하는 데 문제가있는 경우 (.setQueryTimeout을 사용하지 않음) -HouseKeeper 스레드는 어떤 연결이 만료 될 수 있는지 확인하기 전에 연결 테스트를 확인합니다 [다른 시간 초과를 통해 끊어 지거나 종료 될 수있는 만료 된 연결을 테스트 할 위험이 있습니다. 방화벽 내 DB 등] -프로젝트에 미완성 코드가 있음 (정의되었지만 실행되지 않는 속성) -정의되지 않은 경우 기본 최대 연결 수명은 4 시간 (초과)입니다.
-HouseKeeper 스레드는 프로세스에 대한 연결 풀 잠금을 가지고있는 동안 Prototyper 스레드에 연결을 다시 생성 (스윕)하도록 요청하여 경쟁 조건 / 잠금을 초래할 수 있습니다. 이러한 메서드 호출에서 마지막 매개 변수는 루프 동안 항상 sweep : false 여야하며 그 아래에는 sweep : true 만 있어야합니다.
-HouseKeeper는 끝에 하나의 PrototypeController 스윕 만 필요하며 [위에서 언급 한] 더 많은 기능이 있습니다.



-HouseKeeper 스레드는 풀당 5 초마다 실행 (과도)

코드를 수정하고 이러한 개선을 수행 할 수 있습니다. 그러나 2003 년에 만들어져 2008 년에 업데이트 되었기 때문에 hikaricp와 같은 솔루션이 활용하는 거의 10 년 동안의 Java 개선이 부족했습니다.


4

다른 사람들이 대답했듯이 Apache Dbcp 또는 c3p0에 만족할 것입니다. . 둘 다 인기가 있으며 잘 작동합니다.

당신의 의심에 대해

javax.sql 또는 java.sql에 풀링 된 연결 구현이 없습니까? 이것을 사용하는 것이 왜 최선이 아닐까요?

그들은 구현을 제공하지 않고 인터페이스와 일부 지원 클래스를 제공하며 타사 라이브러리 (풀 또는 드라이버)를 구현하는 프로그래머에게만 유용합니다. 일반적으로 당신은 그것을 보지 않습니다. 코드는 "일반"연결 인 것처럼 풀의 연결을 투명한 방식으로 처리해야합니다.


4

Vibur DBCP 는 이러한 목적을위한 또 다른 라이브러리입니다. Hibernate, Spring + Hibernate 또는 프로그래밍 방식으로 사용하도록 구성하는 방법을 보여주는 몇 가지 예제는 웹 사이트에서 찾을 수 있습니다. http://www.vibur.org/ .

또한 여기 에서 면책 조항을 참조 하십시오 .


3

Apache Commons에는이를위한 라이브러리 인 DBCP가 있습니다. 풀 주변에 이상한 요구 사항이 있지 않는 한 라이브러리를 사용하면 원하는 것보다 더 까다 롭고 미묘 할 수 있습니다.


1

UCP 사용을 고려해야합니다. UCP (범용 연결 풀) 는 Java 연결 풀입니다. 풍부한 연결 풀 기능을 제공하며 Oracle의 RAC (Real Application Clusters), ADG, DG 데이터베이스와 긴밀하게 통합됩니다.

UCP에 대한 자세한 내용은 이 페이지 를 참조하십시오.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.