0

以下のコードを書きました - DataSource をシングルトンにして、シングルトンに enum イディオムを使用したいです。しばらくすると、多くのData source rejected establishment of connection, message from server: "Too many connections"エラーが発生します。Singleton パターンの実装が間違っているのでしょうか、それとも原因は別の場所にありますか?

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;

class DBConnectionPool {

    private DataSource ds = null;

    private DBConnectionPool() {
        try {
            Context context = new InitialContext();
            Context envctx = (Context) context.lookup("java:comp/env");
            ds = (DataSource) envctx.lookup("jdbc/TestDB");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static enum PoolSingleton {
        POOL_INSTANCE;

        private static final DBConnectionPool singleton = new DBConnectionPool();

        private DBConnectionPool getSingleton() {
            return singleton;
        }
    }

    private static DBConnectionPool getDBConnectionPoolInstance() {
        return PoolSingleton.POOL_INSTANCE.getSingleton();
    }

    static Connection getConnection() {
        try {
            return getDBConnectionPoolInstance().ds.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        }
    }
}

完全を期すために、 context.xml の内容を次に示します。

<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/myapp">
    <Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"
        maxActive="100" maxIdle="30" maxWait="10000" username="root"
        password="root" factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
        driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/mydb"
        removeAbandoned="true" removeAbandonedTimeout="60" />
</Context>

注意:私は接続プールを実装していません!私はTomcatファクトリーを使用しています。私がしているのは、プールをクラスにラップすることです。プールは、ds一度だけインスタンス化されると思うオブジェクトです。私は、finally ブロックで接続 + セット + ステートメントを閉じます。使用例:

public User findByUsername(String username) throws DBExFailure {
        Connection conn = DBConnectionPool.getConnection();
        PreparedStatement statement = null;
        ResultSet set = null;
        final String query = "SELECT * FROM users WHERE username=?";
        if (conn != null) {
            try {
                statement = conn.prepareStatement(query);
                statement.setString(1, username);
                set = statement.executeQuery();
                while (set.next()) {
                    User user = new User();
                    // user.setId(set.getInt("ID"));
                    user.setUsername(set.getString("username"));
                    user.setName(set.getString("name"));
                    user.setSurname(set.getString("surname"));
                    user.setPassword(set.getString("password"));
                    user.setEmail(set.getString("email"));
                    user.setRole(RolesENUM.values()[set.getInt("role")]);
                    return user;
                }
            } catch (SQLException ex) {
                ex.printStackTrace();
                throw new DBExFailure();
            } finally {
                DBConnectionPool.closeResources(set, statement, conn);
            }
        }
        return null;
    }

どこ :

static void closeResources(ResultSet set, Statement statement,
        Connection conn) {
    if (set != null) {
        try {
            set.close();
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }
    if (statement != null) {
        try {
            statement.close();
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }
    if (conn != null) {
        try {
            conn.close();
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }
}
4

2 に答える 2

5

これを作成する正しい方法は、作成しないことだと言わざるを得ません: C3P0のような既存のライブラリを使用します。

これは、「スマート パンツ」の回答でもありません。これは単に「車輪を再発明しない」ためのものであり、特にスレッドセーフなプールの実装は適切に行うのが難しく、通常、スレッド関連の微妙で修正が難しいバグの地雷原を作成します。

于 2012-09-22T02:34:15.187 に答える
2

あなたのプールはかなり浅いです - 接続は 1 つしかありません! それはどのようにスケーリングしますか?

JNDI 名を配線しました。なぜそれを渡さないのですか?

これは、マルチスレッド アプリケーションにはあまり適していません。接続はスレッドセーフではありません。

あなたが得た最高のアドバイスは、「やらないでください」でした。既存のプールを使用します。または、さらに良いのは、Java EE アプリ サーバーに組み込まれているものです。

于 2012-09-22T02:46:09.087 に答える