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


111

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

グーグルを検索すると、これを実行するさまざまな方法がわかります。

最終的にはjava.sql.Connectionオブジェクトを返すコードが必要ですが、開始に問題があります。

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


8
いいえ、標準のJDBCは接続プールを提供していません。そのためには別のライブラリが必要です。ほとんどのアプリサーバーとサーブレットコンテナーには、接続プールが含まれています。また、JPA実装は通常、実装も提供します。
Will Hartung、

3
現代のJavaユーザー向けのアップデート。JDBC 3.0+(Java 6で使用されていると思いますか?)には、プールされたDB接続の実装があります。Java 7はJDBC 4およびJava 8 JDBC 4.1を使用します。
ブラスムセン2017

1
接続プール用のJDBC 3.0 APIについて:progress.com/tutorials/jdbc/jdbc-jdbc-connection-pooling
Arto Bendiken

回答:


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を取得する必要があります。

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

1
同上、それ。私は何年もの間、負荷のかかった状態でDBCPのデッドロックを観察してきました。バージョンごとのバージョン。
Vasiliy 2013年

ええしかしC3P0も、私はBoneCPで最高の経験を持っていた
ニコラMommaerts

1
BoneCPのように見えるがされた非推奨の賛成でHikariCP。HikariCPは以下の回答でも言及されています
kaartic

19

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

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


18

ひかりCP

それはモダンで、高速で、シンプルです。私はそれをすべての新しいプロジェクトに使用します。私はC3P0よりもずっと好きですが、他のプールについてはあまり知りません。


18

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

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

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

Apache DBCPには、プーリングjavax.sql.DataSourceを設定する方法に関するさまざまな例が付属しています。これは、始めるのに役立つ1つのサンプルです。


1
それはC3P0と呼ばれています。ちなみに、DBCPはシングルスレッドへのアクセスをロックするため、マルチスレッド環境ではDBCPよりもパフォーマンスが優れています。
BalusC 2010年

@BalusC。訂正してくれてありがとうdisclecsia。リンクが正しいことがわかります。:)
Alexander Pogrebnyak 2010年

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

@AlexanderPogrebnyak:アレクサンダー、ありがとうございます。CPをAxis Webサービスで使用する予定です。あなたの提案について考えます。– 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();

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


8
これは実際に接続プールを作成しますか?
llm

@llmもちろん!javax.sql.DataSourceインタフェースの定義「コネクションプーリング「の実装が含まれています(ほかに、私はあなたがすでにJDBCインタフェースが何であるかを知っていると思う)。
エディ

7

私が使用するアプリサーバー(私が覚えているように、Oracle Application Server 10g)で使用するアプリサーバーでは、プーリングはアプリサーバーによって処理されます。でjavax.sql.DataSourceJNDIルックアップを使用してを取得します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プール、String定数プール、Threadプール、接続プール]

文字列定数プール

  • 文字列リテラルプールは、各文字列値のコピーを1つだけ保持します。これは不変でなければなりません。
  • インターンメソッドが呼び出されると、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));
    }
}

タイプ-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つを選択し、それを返します。
  • close() 閉じたのではなく、ラップされた接続をプールに戻します。

例:Java 7で〜DBCP2接続プールを使用する[ try-with-resources]

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    :

Webアプリケーション:基礎となるDBとの接続を再開するために、すべての接続が閉じられたときの接続の問題を回避するには[MySQL "wait_timeout"デフォルト8時間]。

これを行うには、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();    }
}

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


文字列定数プールの例では、「プール内で文字列コピーが利用できる場合は[.equals()]が参照を返します。«そうでない場合は、文字列オブジェクトがプールに追加され、参照が返されます。」しかし、public class StringPoolTestちょうど2つのvoidメソッドがあるため、何も返されません。そのコードは実際に文字列プールを管理するプロセスを通過しますか?引数も使用していないようです。
jeffery_the_wind 2016

@jeffery_the_wind: -それは私だけで使用のhashCode、identityHashCode検証文字列プールのために、ちょうどプールの概念を知ることですmethodes。コードを変更...
Yash

申し訳ありませんが、s1定義されていませんか?
jeffery_the_wind 2016

OK、私がそれをすべて見ていることを確認したかっただけです。私はそれに取り組みます。あなたのConnectionPoolクラスに近いものに必要なもの。本当にありがとう。
jeffery_the_wind 2016

5

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

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

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


4

他の人が答えたように、おそらくApache Dbcpまたはc3p0に満足するでしょう。どちらも人気があり、問題なく動作します。

あなたの疑問について

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

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



3

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



0

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

マルチライセンスのEPLLGPLMPLです。

そのドキュメントには、(DBCPとC3P0に加えて)チェックする価値のある代替案も含まれています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.