正确构建 Jersey WS + Hibernate 以实现并发
Correctly architecting Jersey WS + Hibernate to concurrency
我使用 Jersey 2 和 Hibernate 5 开发了一个 Web 服务。我将解释 Hibernate 的架构。
我使用 Dao 模式:只有一个独特的 DAO,尽管我有几个 类。我还没有创建 Dao 应该实现的任何接口。我认为以前的建筑在建筑方面根本不对。这是我的道:
public class PtDao{
/*
* Atributos
*/
private static PtDao INSTANCE = null;
private Session currentSession;
private Transaction currentTransaction;
private SessionFactory factory;
/*
* Métodos
*/
private PtDao() throws HibernateException, ConfigurationException{
factory = getSessionFactory();
}
public static PtDao getInstance() throws HibernateException, ConfigurationException{
if(INSTANCE == null){
INSTANCE = new PtDao();
}
return INSTANCE;
}
public Session openCurrentSession() throws HibernateException {
currentSession = factory.openSession();
return currentSession;
}
public void closeCurrentSession() {
currentSession.close();
currentSession = null;
}
private SessionFactory getSessionFactory() throws HibernateException, ConfigurationException{
if(getFactory() == null){
Configuration cfg = new Configuration();
cfg.setProperty("hibernate.dialect", "org.hibernate.spatial.dialect.postgis.PostgisDialect");
cfg.setProperty("hibernate.connection.driver_class", "org.postgresql.Driver");
PropertiesConfiguration config = PropertiesConfiguration.getInstance();
String strUrl = "jdbc:postgresql://" + config.getDb_host() + ":" + config.getDb_port() + "/" + config.getDb_database();
cfg.setProperty("hibernate.connection.url", strUrl);
cfg.setProperty("hibernate.connection.username", config.getDb_user());
cfg.setProperty("hibernate.connection.password", config.getDb_passwd());
cfg.setProperty("hibernate.hbm2ddl.auto", "update");
cfg.setProperty("hibernate.show_sql", "false");
cfg.setProperty("hibernate.format_sql", "false");
cfg.setProperty("hibernate.generate_statistics", "false");
// C3p0 connection pool
cfg.setProperty("connection.provider_class", "org.hibernate.connection.C3P0ConnectionProvider");
cfg.setProperty("c3p0.min_size", "7");
cfg.setProperty("c3p0.max_size", "10000");
cfg.setProperty("c3p0.timeout", "1000");
cfg.setProperty("c3p0.idle_test_period", "2000");
cfg.setProperty("c3p0.preferredTestQuery", "select 1;");
cfg.addAnnotatedClass(Tarifa.class);
cfg.addAnnotatedClass(Provincia.class);
cfg.addAnnotatedClass(Comarca.class);
cfg.addAnnotatedClass(Municipio.class);
cfg.addAnnotatedClass(Salto.class);
StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder()
.applySettings(cfg.getProperties());
setFactory(cfg.buildSessionFactory(builder.build()));
}
return getFactory();
}
public Session getCurrentSession() {
return currentSession;
}
public void setCurrentSession(Session currentSession) {
this.currentSession = currentSession;
}
public Transaction getCurrentTransaction() {
return currentTransaction;
}
public void setCurrentTransaction(Transaction currentTransaction) {
this.currentTransaction = currentTransaction;
}
public Transaction beginTransaction(){
this.currentTransaction = currentSession.beginTransaction();
return this.getCurrentTransaction();
}
public void commitTransaction(){
if(currentTransaction != null)
currentTransaction.commit();
}
public void rollbackTransaction(){
if(currentTransaction != null)
currentTransaction.rollback();
}
public SessionFactory getFactory() {
return factory;
}
public void setFactory(SessionFactory factory) {
this.factory = factory;
}
public void finish() throws HibernateException {
Session session = getCurrentSession();
if(session != null)
session.close();
if(factory != null)
factory.close();
}
@SuppressWarnings("unchecked")
public List<Municipio> getMunicipios (){
Query q = currentSession.createQuery("from Municipio");
return q.list();
}
public Municipio getMunicipioByCoor(Point coor) throws NoExisteMunicipioException{
Criteria crit = currentSession.createCriteria(Municipio.class);
crit.add(SpatialRestrictions.contains("geom", coor));
@SuppressWarnings("unchecked")
List<Municipio> l = crit.list();
if (l.isEmpty())
throw new NoExisteMunicipioException(coor);
return l.get(0);
}
public Comarca getComarcaById(Integer pIdComarca) throws NoExisteComarcaException{
Criteria crit = currentSession.createCriteria(Comarca.class);
crit.add(Restrictions.eq("id", pIdComarca));
crit.setMaxResults(1);
@SuppressWarnings("rawtypes")
List comarcas = crit.list();
if(comarcas.isEmpty())
throw new NoExisteComarcaException(pIdComarca);
return (Comarca) comarcas.get(0);
}
public Boolean existenSaltosComarcas(){
Criteria crit = currentSession.createCriteria(Salto.class);
@SuppressWarnings("rawtypes")
List saltos = crit.list();
Boolean tiene = false;
if(saltos != null){
if(!saltos.isEmpty()){
tiene = true;
}
}
return tiene;
}
public void crearSalto(Comarca pComarcaOrigen, Comarca pComarcaDestino, int pNumeroSaltos) {
Salto elSalto = new Salto(pComarcaOrigen, pComarcaDestino, pNumeroSaltos);
currentSession.save(elSalto);
}
public Integer getCantidadSaltos(Municipio municipioInicio, Municipio municipioFin) throws SinViajesEntreZonasException {
System.out.println("getCantidadSaltos()");
Integer saltos = null;
Criteria crit = currentSession.createCriteria(Salto.class);
crit.add(
Restrictions.and(
Restrictions.eq("origen", municipioInicio.getZona_mugi()),
Restrictions.eq("destino", municipioFin.getZona_mugi())
)
);
crit.setMaxResults(1);
@SuppressWarnings("rawtypes")
List res = crit.list();
if(res != null){
if(!res.isEmpty()){
saltos = ((Salto) res.get(0)).getNumeroSaltos();
}else{
throw new SinViajesEntreZonasException(municipioInicio.getZona_mugi(), municipioFin.getZona_mugi());
}
}else{
throw new SinViajesEntreZonasException(municipioInicio.getZona_mugi(), municipioFin.getZona_mugi());
}
return saltos;
}
public Boolean existenTarifas() {
Boolean existen = false;
Criteria crit = currentSession.createCriteria(Tarifa.class);
crit.setProjection(Projections.rowCount());
Long cant = (Long) crit.uniqueResult();
if(cant > 0){
existen = true;
}
return existen;
}
public void crearTarifa(Tarifa pTarifa) {
currentSession.saveOrUpdate(pTarifa);
}
public Tarifa getTarifa(TipoTarifa pTipoTarifa) throws NoExisteTarifaException {
Criteria crit = currentSession.createCriteria(Tarifa.class);
crit.add(Restrictions.idEq(pTipoTarifa));
Tarifa t = (Tarifa) crit.uniqueResult();
if(t == null){
throw new NoExisteTarifaException(pTipoTarifa);
}else{
return t;
}
}
}
我有一个服务层,它执行在 Web 服务端点中启动的操作:
public class PtDaoService {
private PtDao dao;
public PtDaoService() throws HibernateException, ConfigurationException{
dao = PtDao.getInstance();
}
public void finish() throws HibernateException {
dao.finish();
}
public void imprimirZonas(){
try {
dao.openCurrentSession();
List<Municipio> municipios = dao.getMunicipios();
for(Municipio m:municipios){
System.out.println(m.toString());
}
dao.closeCurrentSession();
} catch (HibernateException e) {
System.err.println("Error HibernateException: " + e.getMessage());
e.printStackTrace();
}
}
public Municipio getMunicipioByCoor(Point coor) throws NoExisteMunicipioException{
try {
dao.openCurrentSession();
Municipio municipio = dao.getMunicipioByCoor(coor);
dao.closeCurrentSession();
return municipio;
} catch (HibernateException e) {
System.err.println("Error HibernateException: " + e.getMessage());
e.printStackTrace();
return null;
}
}
public void inicializarTarifasSiNoExisten(){
boolean construyendo = false;
try {
dao.openCurrentSession();
if(!dao.existenTarifas()){
construyendo = true;
dao.beginTransaction();
Tarifa ocasional = new Tarifa(
TipoTarifa.Ocasional,
"Sin condiciones",
Money.of(CurrencyUnit.EUR, 1.70),
Money.of(CurrencyUnit.EUR, 2.45),
Money.of(CurrencyUnit.EUR, 4.65),
Money.of(CurrencyUnit.EUR, 6.85),
Money.of(CurrencyUnit.EUR, 8.90),
Money.of(CurrencyUnit.EUR, 12.00));
dao.crearTarifa(ocasional);
Tarifa tramo1 = new Tarifa(
TipoTarifa.Tramo1,
"Descuento del 45%",
Money.of(CurrencyUnit.EUR, 0.93),
Money.of(CurrencyUnit.EUR, 1.35),
Money.of(CurrencyUnit.EUR, 2.56),
Money.of(CurrencyUnit.EUR, 3.77),
Money.of(CurrencyUnit.EUR, 4.90),
Money.of(CurrencyUnit.EUR, 6.60));
dao.crearTarifa(tramo1);
dao.commitTransaction();
}
dao.closeCurrentSession();
} catch (HibernateException e) {
if(construyendo)
dao.rollbackTransaction();
System.err.println("Error HibernateException: " + e.getMessage());
e.printStackTrace();
}
}
public void inicializarSaltosComarcasSiNoExisten(){
//a method
}
public Integer getCantidadSaltos(Double pOriginLatitude, Double pOriginLongitude, Double pDestinationLatitude,
Double pDestinationLongitude) throws SinViajesEntreZonasException, NoExisteMunicipioException, ErrorEnGetCantidadSaltosException {
System.out.println("getCantidadSaltos() [ pOriginLatitude=" + pOriginLatitude + ", pOriginLongitude=" + pOriginLongitude + ", pDestinationLatitude=" + pDestinationLatitude + ", pDestinationLongitude=" + pDestinationLongitude + " ]");
Point inicio = GeometriesFactory.createPoint(pOriginLatitude, pOriginLongitude);
Point fin = GeometriesFactory.createPoint(pDestinationLatitude, pDestinationLongitude);
try {
dao.openCurrentSession();
Municipio municipioInicio = dao.getMunicipioByCoor(inicio);
Municipio municipioFin = dao.getMunicipioByCoor(fin);
Integer saltos = dao.getCantidadSaltos(municipioInicio, municipioFin);
dao.closeCurrentSession();
return saltos;
} catch (HibernateException e) {
System.err.println("Error HibernateException: " + e.getMessage());
e.printStackTrace();
throw new ErrorEnGetCantidadSaltosException();
}
}
public Money getTarifaDeSaltos(Boolean pTieneTarjeta, Integer pSaltos) throws NoExisteTarifaException, ErrorEnGetTarifaException {
TipoTarifa tipoTarifa;
if(pTieneTarjeta){
tipoTarifa = TipoTarifa.Tramo1;
}else{
tipoTarifa = TipoTarifa.Ocasional;
}
Tarifa laTarifa = null;
try {
dao.openCurrentSession();
laTarifa = dao.getTarifa(tipoTarifa);
dao.closeCurrentSession();
return laTarifa.getTarifaParaLosSaltos(pSaltos);
} catch (HibernateException e) {
System.err.println("Error HibernateException: " + e.getMessage());
e.printStackTrace();
throw new ErrorEnGetTarifaException(tipoTarifa);
}
}
}
这是我端点的一段代码:
@Path("FareManager")
public class TarifasService {
private PtDaoService dao;
...
@ValidateOnExecution
@GET
@Consumes(MediaType.TEXT_PLAIN)
@Produces(MediaType.APPLICATION_JSON)
@Path("{operator}/fare")
public Response getTarifa(
@NotNull @PathParam("operator") String pOperator,
@NotNull @QueryParam("start_lat") Double pOriginLatitude,
@NotNull @QueryParam("start_lon") Double pOriginLongitude,
@NotNull @QueryParam("end_lat") Double pDestinationLatitude,
@NotNull @QueryParam("end_lon") Double pDestinationLongitude,
@QueryParam("user_id") String pUserIdentification,
@QueryParam("provider") String pTransportProvider,
@QueryParam("card") Boolean pCard
){
String json = "";
try {
if(pOperator==null || pOriginLatitude==null || pOriginLongitude==null || pDestinationLatitude==null || pDestinationLongitude==null || pCard==null || pTransportProvider==null){
String[] params = {"operator", "start_lat", "start_lon", "end_lat", "end_lon", "card", "provider"};
throw new ParametrosInsuficientesException(params);
}
Integer saltos = dao.getCantidadSaltos(pOriginLatitude, pOriginLongitude, pDestinationLatitude, pDestinationLongitude);
Money tarifa = dao.getTarifaDeSaltos(pCard, saltos);
BigDecimal precio = tarifa.getAmount();
Currency moneda = tarifa.getCurrencyUnit().toCurrency();
FareResponse response = new FareResponse(pTransportProvider, precio, moneda);
json = mWriter.writeValueAsString(response);
logHelper.logGetTarifa(pOriginLatitude, pOriginLongitude, pDestinationLatitude, pDestinationLongitude, precio, moneda, saltos, pCard, pOperator, pUserIdentification, pTransportProvider);
return Response.ok(json, MediaType.APPLICATION_JSON).build();
} catch (Exception e) {
System.err.println("Error: " + e.getLocalizedMessage());
e.printStackTrace();
ExceptionResponse errResp = new ExceptionResponse(e);
try {
json = mWriter.writeValueAsString(errResp);
return Response.serverError().tag("Error").entity(json).build();
} catch (JsonProcessingException e1) {
System.err.println("Error: " + e.getLocalizedMessage());
e.printStackTrace();
return Response.serverError().tag("Error").build();
}
}
}
问题是 Web 服务应该允许同时对同一方法发出多个请求。如果我一次多次执行一个方法(在浏览器中,例如按几次 f5),我会得到异常痕迹,而且似乎是随机的。
你能看出我的代码有什么问题吗?
提前致谢
编辑
这是例外情况:
14:05:00.135 [http-apr-9090-exec-6] ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper - This statement has been closed.
Error HibernateException: could not extract ResultSet
org.hibernate.exception.GenericJDBCException: could not extract ResultSet
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:97)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:79)
at org.hibernate.loader.Loader.getResultSet(Loader.java:2115)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1898)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1874)
at org.hibernate.loader.Loader.doQuery(Loader.java:919)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:336)
at org.hibernate.loader.Loader.doList(Loader.java:2610)
at org.hibernate.loader.Loader.doList(Loader.java:2593)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2422)
at org.hibernate.loader.Loader.list(Loader.java:2417)
at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:109)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1787)
at org.hibernate.internal.CriteriaImpl.list(CriteriaImpl.java:363)
at com.ingartek.dao.PtDao.getMunicipioByCoor(PtDao.java:192)
at com.ingartek.dao.PtDaoService.getCantidadSaltos(PtDaoService.java:326)
at com.ingartek.ws.tarifas.TarifasService.getTarifa(TarifasService.java:195)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory.invoke(ResourceMethodInvocationHandlerFactory.java:81)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.run(AbstractJavaResourceMethodDispatcher.java:144)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:161)
at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:160)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
at org.glassfish.jersey.server.ServerRuntime.run(ServerRuntime.java:326)
at org.glassfish.jersey.internal.Errors.call(Errors.java:271)
at org.glassfish.jersey.internal.Errors.call(Errors.java:267)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)
at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:473)
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:427)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:388)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:341)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:228)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.logging.log4j.web.Log4jServletFilter.doFilter(Log4jServletFilter.java:71)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2500)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2489)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)
Caused by: org.postgresql.util.PSQLException: This statement has been closed.
at org.postgresql.jdbc.PgStatement.checkClosed(PgStatement.java:893)
at org.postgresql.jdbc.PgStatement.getMaxRows(PgStatement.java:479)
at org.postgresql.jdbc.PgStatement.createResultSet(PgStatement.java:181)
at org.postgresql.jdbc.PgStatement$StatementResultHandler.handleResultRows(PgStatement.java:231)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1947)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:200)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:424)
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:161)
at org.postgresql.jdbc.PgPreparedStatement.executeQuery(PgPreparedStatement.java:114)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:70)
... 65 more
Error: Error a la hora de consultar la cantidad de saltos.
com.ingartek.exception.ErrorEnGetCantidadSaltosException: Error a la hora de consultar la cantidad de saltos.
at com.ingartek.dao.PtDaoService.getCantidadSaltos(PtDaoService.java:336)
at com.ingartek.ws.tarifas.TarifasService.getTarifa(TarifasService.java:195)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory.invoke(ResourceMethodInvocationHandlerFactory.java:81)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.run(AbstractJavaResourceMethodDispatcher.java:144)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:161)
at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:160)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
at org.glassfish.jersey.server.ServerRuntime.run(ServerRuntime.java:326)
at org.glassfish.jersey.internal.Errors.call(Errors.java:271)
at org.glassfish.jersey.internal.Errors.call(Errors.java:267)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)
at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:473)
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:427)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:388)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:341)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:228)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.logging.log4j.web.Log4jServletFilter.doFilter(Log4jServletFilter.java:71)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2500)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2489)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)
我看到 3 个问题:
- 你的交易管理有误
- 您的 dao 不是线程安全的(这是触发您看到的堆栈跟踪的这一点)。
- 您在服务级别隐藏异常
关于 1,您应该在 finally 块中提交 tx / 关闭休眠会话。
关于2,你不能使用单例的字段来存储当前的交易和当前的会话。不完全正确,但有状态对象应该包装在无状态对象的 ThreadLocal 字段中。这管理起来相对复杂,您应该为此使用库(例如 spring-framework tx services)。
关于3,如果服务隐藏了异常,你永远不知道在控制器中是否发生了错误,以及是否应该继续处理...
我使用 Jersey 2 和 Hibernate 5 开发了一个 Web 服务。我将解释 Hibernate 的架构。
我使用 Dao 模式:只有一个独特的 DAO,尽管我有几个 类。我还没有创建 Dao 应该实现的任何接口。我认为以前的建筑在建筑方面根本不对。这是我的道:
public class PtDao{
/*
* Atributos
*/
private static PtDao INSTANCE = null;
private Session currentSession;
private Transaction currentTransaction;
private SessionFactory factory;
/*
* Métodos
*/
private PtDao() throws HibernateException, ConfigurationException{
factory = getSessionFactory();
}
public static PtDao getInstance() throws HibernateException, ConfigurationException{
if(INSTANCE == null){
INSTANCE = new PtDao();
}
return INSTANCE;
}
public Session openCurrentSession() throws HibernateException {
currentSession = factory.openSession();
return currentSession;
}
public void closeCurrentSession() {
currentSession.close();
currentSession = null;
}
private SessionFactory getSessionFactory() throws HibernateException, ConfigurationException{
if(getFactory() == null){
Configuration cfg = new Configuration();
cfg.setProperty("hibernate.dialect", "org.hibernate.spatial.dialect.postgis.PostgisDialect");
cfg.setProperty("hibernate.connection.driver_class", "org.postgresql.Driver");
PropertiesConfiguration config = PropertiesConfiguration.getInstance();
String strUrl = "jdbc:postgresql://" + config.getDb_host() + ":" + config.getDb_port() + "/" + config.getDb_database();
cfg.setProperty("hibernate.connection.url", strUrl);
cfg.setProperty("hibernate.connection.username", config.getDb_user());
cfg.setProperty("hibernate.connection.password", config.getDb_passwd());
cfg.setProperty("hibernate.hbm2ddl.auto", "update");
cfg.setProperty("hibernate.show_sql", "false");
cfg.setProperty("hibernate.format_sql", "false");
cfg.setProperty("hibernate.generate_statistics", "false");
// C3p0 connection pool
cfg.setProperty("connection.provider_class", "org.hibernate.connection.C3P0ConnectionProvider");
cfg.setProperty("c3p0.min_size", "7");
cfg.setProperty("c3p0.max_size", "10000");
cfg.setProperty("c3p0.timeout", "1000");
cfg.setProperty("c3p0.idle_test_period", "2000");
cfg.setProperty("c3p0.preferredTestQuery", "select 1;");
cfg.addAnnotatedClass(Tarifa.class);
cfg.addAnnotatedClass(Provincia.class);
cfg.addAnnotatedClass(Comarca.class);
cfg.addAnnotatedClass(Municipio.class);
cfg.addAnnotatedClass(Salto.class);
StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder()
.applySettings(cfg.getProperties());
setFactory(cfg.buildSessionFactory(builder.build()));
}
return getFactory();
}
public Session getCurrentSession() {
return currentSession;
}
public void setCurrentSession(Session currentSession) {
this.currentSession = currentSession;
}
public Transaction getCurrentTransaction() {
return currentTransaction;
}
public void setCurrentTransaction(Transaction currentTransaction) {
this.currentTransaction = currentTransaction;
}
public Transaction beginTransaction(){
this.currentTransaction = currentSession.beginTransaction();
return this.getCurrentTransaction();
}
public void commitTransaction(){
if(currentTransaction != null)
currentTransaction.commit();
}
public void rollbackTransaction(){
if(currentTransaction != null)
currentTransaction.rollback();
}
public SessionFactory getFactory() {
return factory;
}
public void setFactory(SessionFactory factory) {
this.factory = factory;
}
public void finish() throws HibernateException {
Session session = getCurrentSession();
if(session != null)
session.close();
if(factory != null)
factory.close();
}
@SuppressWarnings("unchecked")
public List<Municipio> getMunicipios (){
Query q = currentSession.createQuery("from Municipio");
return q.list();
}
public Municipio getMunicipioByCoor(Point coor) throws NoExisteMunicipioException{
Criteria crit = currentSession.createCriteria(Municipio.class);
crit.add(SpatialRestrictions.contains("geom", coor));
@SuppressWarnings("unchecked")
List<Municipio> l = crit.list();
if (l.isEmpty())
throw new NoExisteMunicipioException(coor);
return l.get(0);
}
public Comarca getComarcaById(Integer pIdComarca) throws NoExisteComarcaException{
Criteria crit = currentSession.createCriteria(Comarca.class);
crit.add(Restrictions.eq("id", pIdComarca));
crit.setMaxResults(1);
@SuppressWarnings("rawtypes")
List comarcas = crit.list();
if(comarcas.isEmpty())
throw new NoExisteComarcaException(pIdComarca);
return (Comarca) comarcas.get(0);
}
public Boolean existenSaltosComarcas(){
Criteria crit = currentSession.createCriteria(Salto.class);
@SuppressWarnings("rawtypes")
List saltos = crit.list();
Boolean tiene = false;
if(saltos != null){
if(!saltos.isEmpty()){
tiene = true;
}
}
return tiene;
}
public void crearSalto(Comarca pComarcaOrigen, Comarca pComarcaDestino, int pNumeroSaltos) {
Salto elSalto = new Salto(pComarcaOrigen, pComarcaDestino, pNumeroSaltos);
currentSession.save(elSalto);
}
public Integer getCantidadSaltos(Municipio municipioInicio, Municipio municipioFin) throws SinViajesEntreZonasException {
System.out.println("getCantidadSaltos()");
Integer saltos = null;
Criteria crit = currentSession.createCriteria(Salto.class);
crit.add(
Restrictions.and(
Restrictions.eq("origen", municipioInicio.getZona_mugi()),
Restrictions.eq("destino", municipioFin.getZona_mugi())
)
);
crit.setMaxResults(1);
@SuppressWarnings("rawtypes")
List res = crit.list();
if(res != null){
if(!res.isEmpty()){
saltos = ((Salto) res.get(0)).getNumeroSaltos();
}else{
throw new SinViajesEntreZonasException(municipioInicio.getZona_mugi(), municipioFin.getZona_mugi());
}
}else{
throw new SinViajesEntreZonasException(municipioInicio.getZona_mugi(), municipioFin.getZona_mugi());
}
return saltos;
}
public Boolean existenTarifas() {
Boolean existen = false;
Criteria crit = currentSession.createCriteria(Tarifa.class);
crit.setProjection(Projections.rowCount());
Long cant = (Long) crit.uniqueResult();
if(cant > 0){
existen = true;
}
return existen;
}
public void crearTarifa(Tarifa pTarifa) {
currentSession.saveOrUpdate(pTarifa);
}
public Tarifa getTarifa(TipoTarifa pTipoTarifa) throws NoExisteTarifaException {
Criteria crit = currentSession.createCriteria(Tarifa.class);
crit.add(Restrictions.idEq(pTipoTarifa));
Tarifa t = (Tarifa) crit.uniqueResult();
if(t == null){
throw new NoExisteTarifaException(pTipoTarifa);
}else{
return t;
}
}
}
我有一个服务层,它执行在 Web 服务端点中启动的操作:
public class PtDaoService {
private PtDao dao;
public PtDaoService() throws HibernateException, ConfigurationException{
dao = PtDao.getInstance();
}
public void finish() throws HibernateException {
dao.finish();
}
public void imprimirZonas(){
try {
dao.openCurrentSession();
List<Municipio> municipios = dao.getMunicipios();
for(Municipio m:municipios){
System.out.println(m.toString());
}
dao.closeCurrentSession();
} catch (HibernateException e) {
System.err.println("Error HibernateException: " + e.getMessage());
e.printStackTrace();
}
}
public Municipio getMunicipioByCoor(Point coor) throws NoExisteMunicipioException{
try {
dao.openCurrentSession();
Municipio municipio = dao.getMunicipioByCoor(coor);
dao.closeCurrentSession();
return municipio;
} catch (HibernateException e) {
System.err.println("Error HibernateException: " + e.getMessage());
e.printStackTrace();
return null;
}
}
public void inicializarTarifasSiNoExisten(){
boolean construyendo = false;
try {
dao.openCurrentSession();
if(!dao.existenTarifas()){
construyendo = true;
dao.beginTransaction();
Tarifa ocasional = new Tarifa(
TipoTarifa.Ocasional,
"Sin condiciones",
Money.of(CurrencyUnit.EUR, 1.70),
Money.of(CurrencyUnit.EUR, 2.45),
Money.of(CurrencyUnit.EUR, 4.65),
Money.of(CurrencyUnit.EUR, 6.85),
Money.of(CurrencyUnit.EUR, 8.90),
Money.of(CurrencyUnit.EUR, 12.00));
dao.crearTarifa(ocasional);
Tarifa tramo1 = new Tarifa(
TipoTarifa.Tramo1,
"Descuento del 45%",
Money.of(CurrencyUnit.EUR, 0.93),
Money.of(CurrencyUnit.EUR, 1.35),
Money.of(CurrencyUnit.EUR, 2.56),
Money.of(CurrencyUnit.EUR, 3.77),
Money.of(CurrencyUnit.EUR, 4.90),
Money.of(CurrencyUnit.EUR, 6.60));
dao.crearTarifa(tramo1);
dao.commitTransaction();
}
dao.closeCurrentSession();
} catch (HibernateException e) {
if(construyendo)
dao.rollbackTransaction();
System.err.println("Error HibernateException: " + e.getMessage());
e.printStackTrace();
}
}
public void inicializarSaltosComarcasSiNoExisten(){
//a method
}
public Integer getCantidadSaltos(Double pOriginLatitude, Double pOriginLongitude, Double pDestinationLatitude,
Double pDestinationLongitude) throws SinViajesEntreZonasException, NoExisteMunicipioException, ErrorEnGetCantidadSaltosException {
System.out.println("getCantidadSaltos() [ pOriginLatitude=" + pOriginLatitude + ", pOriginLongitude=" + pOriginLongitude + ", pDestinationLatitude=" + pDestinationLatitude + ", pDestinationLongitude=" + pDestinationLongitude + " ]");
Point inicio = GeometriesFactory.createPoint(pOriginLatitude, pOriginLongitude);
Point fin = GeometriesFactory.createPoint(pDestinationLatitude, pDestinationLongitude);
try {
dao.openCurrentSession();
Municipio municipioInicio = dao.getMunicipioByCoor(inicio);
Municipio municipioFin = dao.getMunicipioByCoor(fin);
Integer saltos = dao.getCantidadSaltos(municipioInicio, municipioFin);
dao.closeCurrentSession();
return saltos;
} catch (HibernateException e) {
System.err.println("Error HibernateException: " + e.getMessage());
e.printStackTrace();
throw new ErrorEnGetCantidadSaltosException();
}
}
public Money getTarifaDeSaltos(Boolean pTieneTarjeta, Integer pSaltos) throws NoExisteTarifaException, ErrorEnGetTarifaException {
TipoTarifa tipoTarifa;
if(pTieneTarjeta){
tipoTarifa = TipoTarifa.Tramo1;
}else{
tipoTarifa = TipoTarifa.Ocasional;
}
Tarifa laTarifa = null;
try {
dao.openCurrentSession();
laTarifa = dao.getTarifa(tipoTarifa);
dao.closeCurrentSession();
return laTarifa.getTarifaParaLosSaltos(pSaltos);
} catch (HibernateException e) {
System.err.println("Error HibernateException: " + e.getMessage());
e.printStackTrace();
throw new ErrorEnGetTarifaException(tipoTarifa);
}
}
}
这是我端点的一段代码:
@Path("FareManager")
public class TarifasService {
private PtDaoService dao;
...
@ValidateOnExecution
@GET
@Consumes(MediaType.TEXT_PLAIN)
@Produces(MediaType.APPLICATION_JSON)
@Path("{operator}/fare")
public Response getTarifa(
@NotNull @PathParam("operator") String pOperator,
@NotNull @QueryParam("start_lat") Double pOriginLatitude,
@NotNull @QueryParam("start_lon") Double pOriginLongitude,
@NotNull @QueryParam("end_lat") Double pDestinationLatitude,
@NotNull @QueryParam("end_lon") Double pDestinationLongitude,
@QueryParam("user_id") String pUserIdentification,
@QueryParam("provider") String pTransportProvider,
@QueryParam("card") Boolean pCard
){
String json = "";
try {
if(pOperator==null || pOriginLatitude==null || pOriginLongitude==null || pDestinationLatitude==null || pDestinationLongitude==null || pCard==null || pTransportProvider==null){
String[] params = {"operator", "start_lat", "start_lon", "end_lat", "end_lon", "card", "provider"};
throw new ParametrosInsuficientesException(params);
}
Integer saltos = dao.getCantidadSaltos(pOriginLatitude, pOriginLongitude, pDestinationLatitude, pDestinationLongitude);
Money tarifa = dao.getTarifaDeSaltos(pCard, saltos);
BigDecimal precio = tarifa.getAmount();
Currency moneda = tarifa.getCurrencyUnit().toCurrency();
FareResponse response = new FareResponse(pTransportProvider, precio, moneda);
json = mWriter.writeValueAsString(response);
logHelper.logGetTarifa(pOriginLatitude, pOriginLongitude, pDestinationLatitude, pDestinationLongitude, precio, moneda, saltos, pCard, pOperator, pUserIdentification, pTransportProvider);
return Response.ok(json, MediaType.APPLICATION_JSON).build();
} catch (Exception e) {
System.err.println("Error: " + e.getLocalizedMessage());
e.printStackTrace();
ExceptionResponse errResp = new ExceptionResponse(e);
try {
json = mWriter.writeValueAsString(errResp);
return Response.serverError().tag("Error").entity(json).build();
} catch (JsonProcessingException e1) {
System.err.println("Error: " + e.getLocalizedMessage());
e.printStackTrace();
return Response.serverError().tag("Error").build();
}
}
}
问题是 Web 服务应该允许同时对同一方法发出多个请求。如果我一次多次执行一个方法(在浏览器中,例如按几次 f5),我会得到异常痕迹,而且似乎是随机的。
你能看出我的代码有什么问题吗?
提前致谢
编辑 这是例外情况:
14:05:00.135 [http-apr-9090-exec-6] ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper - This statement has been closed.
Error HibernateException: could not extract ResultSet
org.hibernate.exception.GenericJDBCException: could not extract ResultSet
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:97)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:79)
at org.hibernate.loader.Loader.getResultSet(Loader.java:2115)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1898)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1874)
at org.hibernate.loader.Loader.doQuery(Loader.java:919)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:336)
at org.hibernate.loader.Loader.doList(Loader.java:2610)
at org.hibernate.loader.Loader.doList(Loader.java:2593)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2422)
at org.hibernate.loader.Loader.list(Loader.java:2417)
at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:109)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1787)
at org.hibernate.internal.CriteriaImpl.list(CriteriaImpl.java:363)
at com.ingartek.dao.PtDao.getMunicipioByCoor(PtDao.java:192)
at com.ingartek.dao.PtDaoService.getCantidadSaltos(PtDaoService.java:326)
at com.ingartek.ws.tarifas.TarifasService.getTarifa(TarifasService.java:195)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory.invoke(ResourceMethodInvocationHandlerFactory.java:81)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.run(AbstractJavaResourceMethodDispatcher.java:144)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:161)
at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:160)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
at org.glassfish.jersey.server.ServerRuntime.run(ServerRuntime.java:326)
at org.glassfish.jersey.internal.Errors.call(Errors.java:271)
at org.glassfish.jersey.internal.Errors.call(Errors.java:267)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)
at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:473)
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:427)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:388)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:341)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:228)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.logging.log4j.web.Log4jServletFilter.doFilter(Log4jServletFilter.java:71)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2500)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2489)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)
Caused by: org.postgresql.util.PSQLException: This statement has been closed.
at org.postgresql.jdbc.PgStatement.checkClosed(PgStatement.java:893)
at org.postgresql.jdbc.PgStatement.getMaxRows(PgStatement.java:479)
at org.postgresql.jdbc.PgStatement.createResultSet(PgStatement.java:181)
at org.postgresql.jdbc.PgStatement$StatementResultHandler.handleResultRows(PgStatement.java:231)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1947)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:200)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:424)
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:161)
at org.postgresql.jdbc.PgPreparedStatement.executeQuery(PgPreparedStatement.java:114)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:70)
... 65 more
Error: Error a la hora de consultar la cantidad de saltos.
com.ingartek.exception.ErrorEnGetCantidadSaltosException: Error a la hora de consultar la cantidad de saltos.
at com.ingartek.dao.PtDaoService.getCantidadSaltos(PtDaoService.java:336)
at com.ingartek.ws.tarifas.TarifasService.getTarifa(TarifasService.java:195)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory.invoke(ResourceMethodInvocationHandlerFactory.java:81)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.run(AbstractJavaResourceMethodDispatcher.java:144)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:161)
at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:160)
at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
at org.glassfish.jersey.server.ServerRuntime.run(ServerRuntime.java:326)
at org.glassfish.jersey.internal.Errors.call(Errors.java:271)
at org.glassfish.jersey.internal.Errors.call(Errors.java:267)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)
at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:473)
at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:427)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:388)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:341)
at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:228)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.logging.log4j.web.Log4jServletFilter.doFilter(Log4jServletFilter.java:71)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2500)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2489)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)
我看到 3 个问题:
- 你的交易管理有误
- 您的 dao 不是线程安全的(这是触发您看到的堆栈跟踪的这一点)。
- 您在服务级别隐藏异常
关于 1,您应该在 finally 块中提交 tx / 关闭休眠会话。
关于2,你不能使用单例的字段来存储当前的交易和当前的会话。不完全正确,但有状态对象应该包装在无状态对象的 ThreadLocal 字段中。这管理起来相对复杂,您应该为此使用库(例如 spring-framework tx services)。
关于3,如果服务隐藏了异常,你永远不知道在控制器中是否发生了错误,以及是否应该继续处理...