Tomcat-dbcp データベース接続プールの構成と使用時の落とし穴

黄舟
リリース: 2017-03-02 16:44:01
オリジナル
1601 人が閲覧しました

1. データベース接続プール

開発中、一般的な追加、削除、変更、検索などの操作を実行する必要があることがよくありますが、データ量が少ない場合は、直接実行できます。ただし、データ量が増加すると、データベースの接続と解放にそれぞれ一定の時間がかかります。このとき、データベース接続プールを使用してデータベース リンクを維持し、接続のオーバーヘッドを減らすことができます。データベースをプログラム上で管理し、データベースへの負荷を軽減します。その後、データベース接続プールとはどのようなものですか?名前が示すように、池に置かれているのはデータベースへのリンクです。たとえば、魚を食べたい場合は、魚を飼育することができます。自分で稚魚を買ったり育てたりする必要はありません。データベースへのリンクを保存するために使用されます。使用後はそこから直接リンクを取得できます。これを使用するので、コードを自分で記述する必要はありません。オープン ソース接続プールには、c3p0、dbcp、proxool の 3 つがあります。 c3p0 と proxool は使用したことがありません。単純に dbcp プールを使用したことがあります。ここでは、dbcp データベース接続プールの使用方法と、使用時に遭遇するいくつかの落とし穴について説明します

図 1、接続プールを使用する前



図 2 接続プールの使用後の使用

上の図 1 に示すように、接続プールを使用する前に、毎回データベースへのリンクを確立し、量が増えたらいつでも解放する必要があります。データが大きく、データベースへの接続に多くのオーバーヘッドが必要であり、データベースへのアクセスと解放が頻繁に行われると、データベースに大きな負荷がかかります。図 2 は、データベース接続プールを使用した後にすべてのリンクが配置されることを示しています。使用すると、プールから直接取り出され、リンクが切断された場合はプールに戻されます。接続が十分でない場合、後続のユーザーは待つ必要があります。 2. tomcat-dbcp を使用します。jar パッケージ

には tomcat-dbcp.jar のみが含まれており、残りはいくつかの基本的なパッケージです

3. 使用される構成

dbname.Driver=com.mysql.jdbc.Driver
dbname.Url=jdbc:mysql://<your ip>/<your dbname>?useUnicode=true&characterEncoding=UTF-8
&autoReconnect=true&failOverReadOnly=false&maxReconnects=10&autoReconnectForPools=true&zeroDateTimeBehavior=convertToNull&connectTimeout=3000
dbname.Username=<your username>
dbname.Password=<your password>
dbname.InitialSize=15
dbname.MinIdle=10
dbname.MaxIdle=20
dbname.MaxWait=5000
dbname.MaxActive=20
dbname.validationQuery=select 1
ログイン後にコピー

これらの構成は、.properties に配置する必要があるだけです。それぞれの意味


ここで、ドライバー、URL、ユーザー名、パスワードは一般的なデータベース接続構成です

InitialSize为初始化建立的连接数
ログイン後にコピー
minidle为数据库连接池中保持的最少的空闲的链接数
ログイン後にコピー
maxidle数据库连接池中保持的最大的连接数
ログイン後にコピー
maxwait等待数据库连接池分配连接的最长时间,超出之后报错
ログイン後にコピー
maxactivite最大的活动链接数,如果是多线程可以设置为超出多线程个数个链接数
ログイン後にコピー
<pre name="code" class="java">validationQuery测试是否连接是有效的sql语句
ログイン後にコピー

3. 接続プールコード

public abstract class DB {

    private static HashMap<String, DataSource> dsTable = new HashMap<String, DataSource>();//此处记得用static
    private BasicDataSource ds;
    private PreparedStatement stmt = null;

    private DataSource getDataSource(String n) {
        if (dsTable.containsKey(n)) {
            return dsTable.get(n);//如果不同的数据库,多个连接池
        } else {
        	synchronized (dsTable) {
        		ds = new BasicDataSource();
                ds.setDriverClassName(DBConfig.getString("db", n.concat(".Driver")));//将<yourname>.properties的值读进来
                ds.setUrl(DBConfig.getString("db", n.concat(".Url")));
                ds.setUsername(DBConfig.getString("db", n.concat(".Username")));
                ds.setPassword(DBConfig.getString("db", n.concat(".Password")));
                ds.setInitialSize(DBConfig.getInteger("db", n.concat(".InitialSize")));
                ds.setMinIdle(DBConfig.getInteger("db", n.concat(".MinIdle")));
                ds.setMaxIdle(DBConfig.getInteger("db", n.concat(".MaxIdle")));
                ds.setMaxWait(DBConfig.getInteger("db", n.concat(".MaxWait")));
                ds.setMaxActive(DBConfig.getInteger("db", n.concat(".MaxActive")));
                ds.setValidationQuery(DBConfig.getString("db", n.concat(".validationQuery")));
                dsTable.put(n, ds);

                return ds;
			}
        }
    }

    protected Connection conn;

    public boolean open() throws SQLException {
    	BasicDataSource bds=(BasicDataSource)this.getDataSource(this.getConnectionName());
    	System.out.println("connection_number:"+bds.getNumActive()+"dsTable:"+dsTable);
        this.conn = this.getDataSource(this.getConnectionName()).getConnection();
        return true;
    }

    public void close() throws SQLException {
    	
        if (this.conn != null)
            this.conn.close();
    }

    protected abstract String getConnectionName();//此函数可以根据自己的需求,将数据库的名字传进来即可

    public void prepareStatement(String sql) throws SQLException {
        this.stmt = this.conn.prepareStatement(sql);
    }

    public void setObject(int index, Object value, int type) throws SQLException {
        this.stmt.setObject(index, value, type);
    }

    public void setObject(int index, Object value) throws SQLException {
        this.stmt.setObject(index, value);
    }

    public int execute() throws SQLException {
        return this.stmt.executeUpdate();
    }
}
ログイン後にコピー

上記は、スレッド プールを使用するときに使用されるコードです。これは、バッチ処理、クエリ、更新など、独自の必要に応じて独自に実装する必要がある、一般的な記述方法を示しているだけです。その他の機能は、個人のニーズに応じて変更できます。では、作成したリンクが自分のものであるかどうかを判断するにはどうすればよいでしょうか。確認方法は2つあります

1. 空のデータベースを作成し、リンク数を確認します

プロセスIDを取得します

ps aux|grep <your java name>
ログイン後にコピー

リンクされたデータベースへのリンクを表示します

netstat -apn|grep <your processid>
ログイン後にコピー

詳細を確認できます 接続プールが正しいかどうかを確認するためにリンクの数が使用されます


4. いくつかの落とし穴が発生します


マルチスレッド形式で使用されるため、最も重要な落とし穴が発生します。静的の使用法についてあまり詳しくないので、静的を使用しませんでした。その結果、各スレッドがデータベース接続プールを確立し、「開いているファイルが多すぎます」エラーが発生しました。これは、静的が使用されていないためです。スレッドプールが原因です。

上記は、tomcat-dbcp データベース接続プールの構成と、それを使用する際のいくつかの落とし穴です。その他の関連コンテンツについては、PHP 中国語 Web サイト (www.php.cn) に注意してください。


ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート