10

データベースにアクセスするジャージー リソースがあります。基本的に、リソースの初期化でデータベース接続を開きます。リソースのメソッドに対してクエリを実行します。

@Singleton を使用しない場合、リクエストごとにデータベースが開いていることがわかりました。そして、接続を開くには本当に費用がかかることを知っていますよね?

だから私の質問は、リソースがシングルトンであることを指定する必要がありますか、それとも、特にリソースがデータベースに接続しているときに、リクエストごとに保持する方が本当に良いですか?

私のリソース コードは次のようになります。

//Use @Singleton here or not?
@Path(/myservice/)
public class MyResource {

    private ResponseGenerator responser;
    private Log logger = LogFactory.getLog(MyResource.class);

    public MyResource() {
        responser = new ResponseGenerator();
    }

    @GET
    @Path("/clients")
    public String getClients() {

        logger.info("GETTING LIST OF CLIENTS");

        return responser.returnClients();
    }

    ...
    // some more methods
    ...

}

そして、次のようなコードを使用してデータベースに接続します。

public class ResponseGenerator {
    private Connection conn;
    private PreparedStatement prepStmt;
    private ResultSet rs;

    public ResponseGenerator(){
        Class.forName("org.h2.Driver");
        conn = DriverManager.getConnection("jdbc:h2:testdb");
    }

    public String returnClients(){
        String result;
        try{
           prepStmt = conn.prepareStatement("SELECT * FROM hosts");

           rs = prepStmt.executeQuery();

           ...
           //do some processing here
           ...
        } catch (SQLException se){
            logger.warn("Some message");
        } finally {
            rs.close();
            prepStmt.close();
            // should I also close the connection here (in every method) if I stick to per request
            // and add getting of connection at the start of every method
            // conn.close();
        }

        return result
    }

    ...
    // some more methods
    ...

}

コードのベスト プラクティスに関するコメントも役立ちます。

4

2 に答える 2

0

リソースをシングルトンにすることを考えるのではなく、バックエンド、ResponseGeneratorクラスなどのサービス タイプ オブジェクトをシングルトンとして管理することに重点を置きます。

リソースをシングルトンにすることもシングルトンとして管理する方法の 1 つですResponseGeneratorが、これが唯一の方法ではなく、必ずしも最良の方法でもありません。Jersey リソース クラスで外部オブジェクトにアクセスする方法とコラボレーターをジャージー リソースに接続する方法を参照してくださいこれをシングルトン以外のリソースに注入する方法について。

ResponseGeneratorクラスは、リクエストごとのリソースに注入されるか、シングルトン リソースでインスタンス化されるかに関係なく、シングルトンとして機能する前に作業が必要になることに注意してください。スレッドセーフではなく、起動時に単一の接続を開き、リクエスト間で再利用しますが、これは機能しません。接続プールを使用して、リクエスト間で接続を効率的に安全に再利用するという面倒な作業を行う必要があります。

コードのベスト プラクティスに関するコメントも役立ちます。

http://codereview.stackexchange.comでより良い応答が得られますが、次のようになります。

  • ResponseGeneratorクラスの名前としては不適切です (Web アプリケーションのほとんどすべてが応答ジェネレーターです)。

  • サービスとオブジェクトの戻り値の型として String を使用しないでください。適切な型付きオブジェクトを使用してください (たとえば、何かの を返しているように聞こえますjava.util.List)。

  • SQLException を飲み込まないでください。Jersey がリソースで 5xx シリーズの応答コードを生成できるようにバブルアップしてください。

  • 最終メンバー変数を使用します。

  • ログ オブジェクトは静的である必要があります。

于 2016-09-17T22:48:43.463 に答える
-4

最良の選択肢は、Spring のようなフレームワークを Jersey で使用することです。これについては、同様の投稿で概説しました。唯一の違いは、サービス Bean を注入する代わりに、プールされた DataSource を注入することであり、これはc3p0を使用して簡単に構成できます。

applicationContext.xml の例では、「スコープ」がプロトタイプに設定されていることに注意してください。これは、Spring 用語のシングルトンに相当します。

<bean id="pooledDataSource" scope="prototype" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
    <property name="jdbcUrl" value="${jpa.url}" />
    <property name="user" value="${jpa.username}" />
    <property name="password" value="${jpa.password}" />
    <property name="initialPoolSize" value="1" />
    <property name="minPoolSize" value="1" />
    <property name="maxPoolSize" value="3" />
    <property name="idleConnectionTestPeriod" value="500" />
    <property name="acquireIncrement" value="1" />
    <property name="maxStatements" value="50" />
    <property name="numHelperThreads" value="1" />
</bean>

MyResource.java に以下を追加するだけで、Spring が適切に挿入します。

private DataSource pooledDataSource;
public void setPooledDataSource(DataSource pooledDataSource) {
    this.pooledDataSource = pooledDataSource;
}

次に、ResponseGenerator を変更して DataSource を受け入れ、これを使用してデータベースにクエリを実行できます。

于 2010-05-20T21:05:14.543 に答える