我有一个访问数据库的Jersey资源。基本上它在资源的初始化中打开数据库连接。对资源的方法执行查询。
我观察到当我不使用@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 :(得分:0)
与其考虑使资源成为单身,而不是更多地关注管理后端,服务类型对象,如ResponseGenerator
类作为单例,显然不应该在每个请求中实例化。
将资源设置为单身也是将ResponseGenerator
作为单身人士进行管理的一种方式,但它不是唯一或必然是最好的方式,请参阅Access external objects in Jersey Resource class和{{3}用于将其注入非单例资源的方法。
请注意,您的ResponseGenerator
类在作为单例之前需要工作,无论是注入每个请求资源还是在单例资源中实例化。它不是线程安全的,你可以在启动时打开一个连接并在请求之间重复使用它,这不会起作用,你应该使用一个连接池来有效地重新安全地重复使用连接请求。
有关代码最佳做法的一些评论也会有所帮助。
您会在How to wire in a collaborator into a Jersey resource?上得到更好的回复, 但是:
ResponseGenerator
是一个糟糕的类名(几乎Web应用程序中的所有内容都是响应生成器)。
不要使用String作为服务和对象的返回类型,使用正确的类型对象(例如,它听起来像是“返回java.util.List
某事物”。
不要吞下你的SQLException,冒泡它以允许泽西岛在你的资源中生成一个5xx系列的响应代码。
使用最终成员变量。
您的日志对象应该是静态的。
答案 1 :(得分:-4)
你最好的选择是使用像Jersey一样的框架,我在类似的post中概述了这个框架。唯一的区别是,不是注入服务bean,而是注入一个池化的DataSource,这可以使用c3p0轻松配置。
示例applicationContext.xml,注意“scope”设置为prototype,它相当于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并使用它来查询数据库。