Spring JdbcTemplate 线程安全吗?
Is Spring JdbcTemplate thread safe?
我在我的一个项目中使用 Spring JdbcTemplate,现在,当确实有很多请求时 - 我开始面对这个异常:
org.springframework.jdbc.UncategorizedSQLException: CallableStatementCallback;
uncategorized SQLException for SQL [{? = call API.get_data_for_nb(?, ?)}];
SQL state [99999]; error code [17009]; Closed Statement;
nested exception is java.sql.SQLException: Closed Statement
因此,当您尝试执行已经关闭的语句时会收到 Closed Statement 异常,但在我的情况下,我不会自己关闭它 - 我正是为此使用了 JdbcTemplate。那么,首先,这可能是什么原因?
JdbcTemplate 对象本身以这种方式包含在 @Stateless
EJB 中:
@Stateless(name = "NbEdwServiceEJB")
public class NbEdwServiceBean implements NbEdwServiceLocal, NbEdwServiceRemote {
@Resource(mappedName = JNDI)
private DataSource dataSource;
private static volatile JdbcTemplate jdbcTemplate;
@PostConstruct
protected void construct() {
synchronized (NbEdwServiceBean.class) {
if (jdbcTemplate == null) {
jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.setResultsMapCaseInsensitive(true);
}
}
}
private String getDataFromDB(final String request, final int isDigitalSignVerified) {
String response = null;
try {
response = jdbcTemplate.execute(SQL_GET_DATA, new CallableStatementCallback<String>() {
public String doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {
cs.registerOutParameter(1, Types.VARCHAR);
cs.setInt(2, isDigitalSignVerified);
cs.setString(3, request);
cs.executeUpdate();
return cs.getString(1);
}
});
} catch (DataAccessException ex) {
LOGGER.error("getDataFromDB()", ex);
}
return response;
}
}
我知道这可能不是严格正确的方法,我可以为每个无状态 bean 创建 JdbcTemplate 实例 - 所以我可能会这样做。那么,其次,为什么会发生这种情况?我的假设是 JdbcTemplate 的 execute 方法不是线程安全的,但是有人可以给出完整的解释吗?
如果有问题,我在 WebLogic 10.3.5 上安装了 JEE 版本 5 运行。
@Tolegen Izbassar 很抱歉您被 EE5 困住了。
关于 Singleton 和 EE5,有一些替代方案。一种是特定于供应商的扩展,例如 JBoss 5.x 有提供 Singleton+JMX 的服务 bean。第二种解决方案是使用与 EE5 兼容的 Jboss Seam 的早期版本。第三种选择是使用 Servlet API 中的 ServerContext。
你在@PostConstuct 中尝试做的事情肯定不好。 SLSB 中的非最终静态是不行的。
我建议看一下 Spring 框架参考中描述 EJB - Spring 集成的第 29.3 节,该节中的一个示例:
@Stateless
@Interceptors(SpringBeanAutowiringInterceptor.class)
public class MyFacadeEJB implements MyFacadeLocal {
// automatically injected with a matching Spring bean
@Autowired
private MyComponent myComp;
// for business method, delegate to POJO service impl.
public String myFacadeMethod(...) {
return myComp.myMethod(...);
}
我在我的一个项目中使用 Spring JdbcTemplate,现在,当确实有很多请求时 - 我开始面对这个异常:
org.springframework.jdbc.UncategorizedSQLException: CallableStatementCallback;
uncategorized SQLException for SQL [{? = call API.get_data_for_nb(?, ?)}];
SQL state [99999]; error code [17009]; Closed Statement;
nested exception is java.sql.SQLException: Closed Statement
因此,当您尝试执行已经关闭的语句时会收到 Closed Statement 异常,但在我的情况下,我不会自己关闭它 - 我正是为此使用了 JdbcTemplate。那么,首先,这可能是什么原因?
JdbcTemplate 对象本身以这种方式包含在 @Stateless
EJB 中:
@Stateless(name = "NbEdwServiceEJB")
public class NbEdwServiceBean implements NbEdwServiceLocal, NbEdwServiceRemote {
@Resource(mappedName = JNDI)
private DataSource dataSource;
private static volatile JdbcTemplate jdbcTemplate;
@PostConstruct
protected void construct() {
synchronized (NbEdwServiceBean.class) {
if (jdbcTemplate == null) {
jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.setResultsMapCaseInsensitive(true);
}
}
}
private String getDataFromDB(final String request, final int isDigitalSignVerified) {
String response = null;
try {
response = jdbcTemplate.execute(SQL_GET_DATA, new CallableStatementCallback<String>() {
public String doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {
cs.registerOutParameter(1, Types.VARCHAR);
cs.setInt(2, isDigitalSignVerified);
cs.setString(3, request);
cs.executeUpdate();
return cs.getString(1);
}
});
} catch (DataAccessException ex) {
LOGGER.error("getDataFromDB()", ex);
}
return response;
}
}
我知道这可能不是严格正确的方法,我可以为每个无状态 bean 创建 JdbcTemplate 实例 - 所以我可能会这样做。那么,其次,为什么会发生这种情况?我的假设是 JdbcTemplate 的 execute 方法不是线程安全的,但是有人可以给出完整的解释吗?
如果有问题,我在 WebLogic 10.3.5 上安装了 JEE 版本 5 运行。
@Tolegen Izbassar 很抱歉您被 EE5 困住了。
关于 Singleton 和 EE5,有一些替代方案。一种是特定于供应商的扩展,例如 JBoss 5.x 有提供 Singleton+JMX 的服务 bean。第二种解决方案是使用与 EE5 兼容的 Jboss Seam 的早期版本。第三种选择是使用 Servlet API 中的 ServerContext。
你在@PostConstuct 中尝试做的事情肯定不好。 SLSB 中的非最终静态是不行的。
我建议看一下 Spring 框架参考中描述 EJB - Spring 集成的第 29.3 节,该节中的一个示例:
@Stateless
@Interceptors(SpringBeanAutowiringInterceptor.class)
public class MyFacadeEJB implements MyFacadeLocal {
// automatically injected with a matching Spring bean
@Autowired
private MyComponent myComp;
// for business method, delegate to POJO service impl.
public String myFacadeMethod(...) {
return myComp.myMethod(...);
}