2010-05-01 79 views
9

我有一个Jersey资源可以访问数据库。基本上它会在资源初始化时打开一个数据库连接。对资源的方法执行查询。何时在Jersey资源中使用@Singleton

我观察到,当我不使用@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 
    ... 

} 

上的代码的最佳做法有些意见也将是有益的。

+0

连接池怎么样?你为什么不使用它? – 2010-05-01 09:17:52

回答

-4

您最好的选择是使用像Spring与泽西这是我在一个类似的post提出了一个框架。唯一的区别是,不是注入一个服务bean,而是注入一个池数据源,这可以很容易地使用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并使用它来查询数据库。

0

没有考虑将资源设置为单例,而是更多地关注管理后端,服务类型对象(如ResponseGenerator类)作为单例,这显然不应该在每个请求中都实例化。

使得资源单身以及是管理ResponseGenerator作为一个单独的一种方式,但不是唯一的或者一定是最好的方式,请参阅Access external objects in Jersey Resource classHow to wire in a collaborator into a Jersey resource?的途径注入到非单资源这一点。

请注意,您的ResponseGenerator类在作为单例使用之前需要工作,无论是注入到每个请求资源还是在单例资源中实例化。它不是线程安全的,并且您将在启动时打开单个连接,并跨请求重用它,这将无法工作,您应该使用连接池高效完成+安全地重用跨请求的连接。

上的代码的最佳做法有些意见也将是有益的。

你会得到更好的反应上http://codereview.stackexchange.com, 但:

  • ResponseGenerator是一类的不良域名(只是在Web应用程序一切都响应产生)。

  • 不要使用字符串作为你的服务和对象的返回类型,使用正确的类型对象(例如,它听起来像你返回的东西java.util.List)。

  • 不要吞下你的SQLException,让它沸腾起来,让Jersey在你的资源中生成一个5xx系列响应代码。

  • 使用最终成员变量。

  • 您的日志对象应该是静态的。

相关问题