5

私はまだ同じ問題の言及に取り組んでいます here . 以下に示す AbstractModel クラスを作成した後は、特に問題なく動作するようです。

public abstract class AbstractModel {

    protected static Connection myConnection = SingletonConnection.instance().establishConnection();
    protected static Statement stmt;
    protected static ResultSet rs;

    protected boolean loginCheck;                   // if userId and userLoginHistoryId are valid - true, else false
    protected boolean userLoggedIn;                 // if user is already logged in - true, else false

    public AbstractModel (int userId, Long userLoginHistoryId){
        createConnection();                                 // establish connection
            loginCheck = false;
        userLoggedIn = false;
        if (userId == 0 && userLoginHistoryId == 0){        // special case for login
            loginCheck = true;                              // 0, 0, false, false
            userLoggedIn = false;                           // set loginCheck to true, userLogged in to false
        } else {
            userLoggedIn = true;
            try{
                String query = "select \"user_login_session_check\"(" + userId + ", " + userLoginHistoryId + ");";
                System.out.println("query: " + query);
                stmt = myConnection.createStatement();
                rs = stmt.executeQuery(query);
                while (rs.next()){
                    loginCheck = rs.getBoolean(1);
                }
            } catch (SQLException e){
                System.out.println("SQL Exception: ");
                e.printStackTrace();
            }
        }

    }
    // close connection
    public void closeConnection(){
        try{
            myConnection.close();
        } catch (SQLException e){
            System.out.println("SQL Exception: ");
            e.printStackTrace();
        }

    }
    // establish connection
    public void createConnection(){
        myConnection = SingletonConnection.instance().establishConnection();
    }

    // login session check
    public boolean expiredLoginCheck (){
        if (loginCheck == false && userLoggedIn == true){
            closeConnection();
            return false;
        } else {
            return true;
        }
    }

}

上記の以前の質問へのリンクに、ストアド プロシージャとシングルトン パターンの実装を既に投稿しました。

アプリケーションの速度が低下するだけなので、データ トランザクションごとにデータベースへの接続を閉じる必要はないという印象を受けました。私が構築しているこのシステムのユーザー数は約 30 人なので、パフォーマンスと使いやすさが重要です。

少なくとも 3 ~ 4 データ トランザクションの接続を延長することは正しいですか? 例えば。何らかのフォームのユーザー入力に対する検証チェック、またはGoogleの自動提案に似たもの...これらはすべて、ユーザー入力に基づいて保存された個別の関数呼び出しです。各データ トランザクションの後に接続および切断する代わりに、1 つの接続インスタンスを使用できますか? どちらがより効率的ですか?

私の仮定が正しければ (1 つの接続インスタンスを使用する方が効率的です)、接続の開閉はコントローラーで処理する必要があります。そのため、createConnection() メソッドと closeConnection() メソッドを作成しました。

ありがとう。

4

4 に答える 4

5

アプリケーションが現在データベースに対する唯一のクライアントである、またはユーザーが 30 人しかいないという事実に、コードを依存させてはなりません。したがって、ファイル、ソケット、および実行する可能性のある他のすべての種類の希少なリソースなどのデータベース接続を処理する必要があります。

したがって、常に後片付けをする必要があります。あなたが何をしても。接続を開き、自分の作業 (1 つまたは SQL ステートメント) を実行して、接続を閉じます。いつも!

コードで接続を作成し、それを静的変数に保存します。この接続は、AbstractModel クラスが存在する限り、おそらく永遠に続きます。これは悪いことです。すべての同様のケースと同様に、try/finally 内にコードを配置して、接続が常に閉じられるようにします。

Web アプリケーションが接続を閉じていないために、アプリケーション サーバーが接続不足で実行されているのを見てきました。または、ログアウト時に閉じられ、誰かが「これ以上のユーザーを同時に持つことは決してないだろう」と言いましたが、少しスケールアップしただけです。

zaskeが言ったように、コードを実行して接続を適切に閉じると、接続プールが追加されます。これにより、データベース接続のオープン/クローズのパフォーマンスの問題が解決されますが、これは本当にコストがかかります。論理レイヤー(アプリケーション)では、物理接続をいつ開閉するかを知りたくない場合、dbレイヤー(dbプール)がそれを処理します。

その後、セッション モデル全体に​​対して単一の接続をセットアップすることもできます。これは DBCP でもサポートされています。クライアント コードに触れることなく、必要に応じて後でプールを再構成できるため、これは危険ではありません。

于 2012-06-26T07:23:34.273 に答える
4

Tomasz が言ったように、アプリケーションが少数のクライアントによって使用されるという事実に依存するべきではありません ドライバー一定時間後にタイムアウトするという事実は、十分な接続が利用できることを保証するものではありません。これを想像してみてください: 多くのデータベースは、(たとえば) 15 に設定された最大接続数と (たとえば) 10 ~ 15 分のタイムアウトで事前構成されています。30 のクライアントがあり、それぞれが操作を行う場合、途中で接続が不足することになります。

接続、ファイル、ストリーム、およびその他のリソースを次の方法で処理する必要があります。

public void doSomething()
{
    Connection connection = null;
    Statement stmt = null;
    ResultSet rs = null;

    final String sql = "SELECT ....");

    try
    {
        connection = getConnection();
        stmt = connection.createStatement();

        rs = stmt.executeQuery(sql);
        if (rs.next())
        {
            // Do something here...
        }
    }
    catch (SQLException e)
    {
        e.printStackTrace();
    }
    finally
    {
        closeResultSet(rs);
        closeStatement(stmt);
        closeConnection(connection);
    }
}

try/catch/finally は、結果に関係なく接続が閉じられることを保証します。なんらかの障害が発生した場合でも、正常な場合と同様に、finally ブロックは接続を閉じます。

同様に、ファイルとストリームでも同じことを行う必要があります。それぞれのオブジェクトをnulltry/catch/finally の外として初期化し、上記のアプローチに従います。

この誤解により、多くの Java アプリケーションが Windows で不適切な動作をするようになります。Windows では、人々はファイル (ファイルへのストリームなど) を閉じず、これらのファイルがロックされ、JVM を強制終了するか、マシンを再起動する必要さえあります。

たとえば Apache の DBCP などの接続プールを使用することもできますが、内部的には異なる接続プールの実装が必ずしも接続を閉じるとは限らないにもかかわらず、リソースを閉じるように注意する必要があります。

于 2012-06-26T07:47:44.640 に答える
0

これは、すべてのモデルの myConenction フィールドを初期化するシングルトン パターンです。

public class DatabaseConnection {
    private static final String uname = "*******";
    private static final String pword = "*******";
    private static final String url = "*******************************";

    Connection connection;
    // load jdbc driver
    public DatabaseConnection(){
        try{
            Class.forName("org.postgresql.Driver");
            establishConnection();
        } catch (ClassNotFoundException ce) {
            System.out.println("Could not load jdbc Driver: ");
            ce.printStackTrace();
        }
    }
    public Connection establishConnection() {
        // TODO Auto-generated method stub
        try{
            connection = DriverManager.getConnection(url, uname, pword);
        } catch (SQLException e){
            System.out.println("Could not connect to database: ");
            e.printStackTrace();
        }
        return connection;
    }
}

public class SingletonConnection {

    private static DatabaseConnection con;

    public SingletonConnection(){}

    public static DatabaseConnection instance(){

        assert con == null;
            con = new DatabaseConnection();
        return con;
    }
}

もちろん、アプリからデータベースへのすべての接続はモデルを経由します。

于 2012-06-26T09:46:59.807 に答える
0

通話のたびに接続を閉じる必要がないことは正しいです。
最新のデータベースは内部接続プールを実装していますが、アプリケーションは依然として接続オブジェクトに接続して取得する必要があり、これが現在行われていることです。
データベース接続プールの使用を検討する必要があります。このようなソリューションを提供するさまざまな Java フレームワークがあり、データベース接続プールが閉じられるタイミングを定義します (もちろん、構成できます)。

一般に、データベースが自分のアプリケーションだけにサービスを提供するのか、それとも他のアプリケーションにもサービスを提供するのかを自問する必要があります。他のアプリケーションにもサービスを提供しない場合は、より「貪欲」になり、接続を開いたままにしておくことができます。より長い時間。
また、アプリケーションが開始時に一定数の接続を作成し (構成で「最小接続数」の値を使用して定義します)、必要に応じて最大接続数まで拡張できるようにすることをお勧めします。前に述べたように、アイデアは、Apache のDBCPプロジェクト

など、あらゆる種類のフレームワークによって既に実装されていることが示唆されています。

于 2012-06-26T07:05:31.620 に答える