web-dev-qa-db-ja.com

JDBCで接続プールを確立する方法は?

JDBC接続プールを確立する方法の例やリンクを提供できますか?

グーグルを検索すると、これを行うためのさまざまな方法がわかりますが、かなり混乱しています。

最終的にはJava.sql.Connectionオブジェクトを返すコードが必要ですが、始めるのに苦労しています。

更新:javax.sqlまたはJava.sqlは接続実装をプールしていませんか?これらを使用するのが最善ではないのはなぜですか?

104
llm

スタンドアロンの接続プールが必要な場合、私の好みは C3P over DBCP (この中で言及したこと 前の回答 )、負荷が大きい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を取得する必要があります。

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

通常、接続プールが必要な場合は、何らかの管理環境で実行するアプリケーション、つまりアプリケーションサーバー内で実行するアプリケーションを作成します。この場合、他のオプションを試す前に、アプリケーションサーバーが提供する接続プーリング機能を確認してください = .

すぐに使用できるソリューションは、残りのアプリケーションサーバー機能との最適な統合になります。ただし、アプリケーションサーバー内で実行していない場合は、Apache Commons DBCP Componentをお勧めします。広く使用されており、ほとんどのアプリケーションに必要なすべての基本的なプーリング機能を提供します。

18
Tendayi Mawushe

車輪を再発明しないでください。

すぐに利用できるサードパーティコンポーネントのいずれかを試してください。

  • Apache DBCP -これはTomcatによって内部的に使用され、実際にTomcatによって使用されます。
  • c3p

Apache DBCPには、プーリング javax.sql.DataSource のセットアップ方法に関する別の例が付属しています。ここに、1つ sample があり、これが開始に役立ちます。

16

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

データソースを作成する必要があるのは1回だけなので、その方法がわからない場合は必ずドキュメントを読んでください。リソースをリークしないようにJDBCステートメントを適切に記述する方法を知らない場合は、この Wikipedia ページも読むことをお勧めします。

16
Eric Hauser

HikariCP

モダンで、高速で、シンプルです。新しいプロジェクトごとに使用します。私はC3P0よりもずっと好きです。他のプールをよく知らないのです。

16
tobijdc

私が使用しているアプリサーバーでは(私が思い出すと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());
}

(このコードは記述しませんでした。 このドキュメント からコピーされています。)

7
Powerlord

2017年後半、Proxool、BoneCP、C3P0、DBCPは現在ほとんど機能していません。 HikariCP(2012年に作成)は有望なようで、私が知っている他のあらゆるものから扉を吹き飛ばします。 http://www.baeldung.com/hikaricp

Proxoolにはいくつかの問題があります。
-負荷が高い場合、接続の最大数を超えることがあり、最大以下に戻らない
-接続が期限切れになった後でも最小接続に戻らないように管理できます
-HouseKeeperスレッド中にデータベースへの接続に問題がある場合(.setQueryTimeoutを使用しないでください)、プール全体(およびすべてのサーバー/クライアントスレッド)をロックできます。
-HouseKeeperスレッドは、プロセスの接続プールをロックしている間、Prototyperスレッドに接続の再作成(スイープ)を要求します。これにより、競合状態/ロックアップが発生する可能性があります。これらのメソッド呼び出しでは、ループ中の最後のパラメーターは常にsweep:falseである必要があり、その下のsweep:trueのみです。
-HouseKeeperには、最後に1つのPrototypeControllerスイープのみが必要で、さらに[上記]があります
-HouseKeeperスレッドは、どの接続が期限切れになる可能性があるかを確認する前に、接続のテストをチェックします[ファイアウォール内のDBへの他のタイムアウトなどで切れる/終了する可能性がある期限切れの接続をテストするリスクがあります]
-プロジェクトには未完成のコードがあります(定義されているが実行されていないプロパティ)
-定義されていない場合のデフォルトの最大接続寿命は4時間です(過剰)
-HouseKeeperスレッドはプールごとに5秒ごとに実行されます(過剰)

コードを変更して、これらの改善を行うことができます。しかし、2003年に作成され、2008年に更新されたため、hikaricpなどのソリューションが利用するJavaの改善が10年近くありませんでした。

5
bluejaguar

プール

  • プーリングメカニズムは、オブジェクトを事前に作成する方法です。クラスがロードされたとき。
  • アプリケーションを改善しますperformance[同じオブジェクトを使用して、Object-Dataでアクションを実行する]&memory[多くのオブジェクトの割り当てと割り当て解除により、メモリ管理の大幅なオーバーヘッドが発生します]。
  • 同じオブジェクトを使用しているため、オブジェクトのクリーンアップは不要で、ガベージコレクションの負荷が軽減されます。

"プーリング[ Object pool、 String Constant Pool、 Thread Pool、Connection pool]

文字列定数プール

  • 文字列リテラルプールは、個別の文字列値のコピーを1つだけ保持します。不変でなければなりません。
  • Internメソッドが呼び出されると、equalsメソッドを使用して、プール内の同じコンテンツでオブジェクトの可用性を確認します。 "文字列コピーがプールで使用可能な場合、参照を返します。 "それ以外の場合、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));
    }
}

Type-4を使用した接続プール ドライバーサードパーティライブラリを使用[ DBCP2c3p0Tomcat JDBC ]

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

接続プールメカニズムでは、クラスがロードされると、クラスは physical JDBC connection オブジェクトを取得し、ラップされた物理接続オブジェクトをユーザーに提供します。 PoolableConnection は実際の接続のラッパーです。

  • getConnection()接続から自由にラップされた接続の1つを選択 objectpool し、それを返します。
  • 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:myDBNamejdbc:- mysql://localhost:3306/myDBName

connectionpool.properties

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

Web アプリケーション:すべての接続が閉じられたときの接続問題を回避するために[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();    }
}

これらも参照してください。

5
Yash

他の人が答えたように、おそらく Apache Dbcp または c3p に満足するでしょう。どちらも人気があり、正常に機能します。

あなたの疑いについて

Javax.sqlまたはJava.sqlには、プールされた接続実装がありませんか?これらを使用するのが最善ではないのはなぜですか?

それらは実装を提供せず、むしろインターフェースといくつかのサポートクラスを提供し、サードパーティのライブラリー(プールまたはドライバー)を実装するプログラマーにのみ有益です。通常、あなたもそれを見ません。コードは、プールからの接続を、「プレーン」接続であるかのように透過的に処理する必要があります。

4
leonbloy

Vibur DBCPは、そのための別のライブラリです。 Hibernate、Spring + Hibernate、またはプログラムで使用するための設定方法を示すいくつかの例は、そのWebサイトで見つけることができます。 http://www.vibur.org/

また、免責事項 here を参照してください。

4
Simeon Malchev

Apache Commonsには、そのためのライブラリ DBCP があります。プールの周りに奇妙な要件がない限り、ライブラリは期待以上に巧妙で微妙なものになりがちなので、ライブラリを使用します。

3
sblundy

UCPの使用を検討する必要があります。 ユニバーサル接続プール(UCP) はJava接続プールです。機能豊富な接続プールであり、OracleのReal Application Clusters(RAC)、ADG、DGデータベースと緊密に統合されています。

UCPの詳細については、これを参照してください page .

1
Nirmala

MiniConnectionPoolManager は、組み込み可能なソリューションを探していて、パフォーマンスをあまり気にしない場合(1つのJavaファイルの実装です)(その点についてはテストしていませんが)。

これはマルチライセンスです EPLLGPL および MPL

また、そのドキュメントには、チェックする価値のある選択肢があります(DBCPおよびC3P0に加えて)。

0
Matthieu