请原谅我在此之前从未发布的此帖子的不正确格式。我有一个Spring MVC Web服务运行,调用几个使用JPA / hibernate与SQL Server数据库交互的DAO。在Web服务运行一段时间后,与数据库的连接似乎已关闭。
其中一个DAO类的示例如下:
@Repository
public class OceanClientDaoImpl {
// Create entity manager objects that will talk to the database
private EntityManagerFactory entityManagerFactory;
/**
* Load all clients in the database. Return as ClientLight objects.
*
* @return List of ClientLight objects.
*/
public List<Client> loadClients()
{
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
List<?> clients =
entityManager.createNativeQuery("select id, clientname, industry, logo, slug from client",
Client.class).getResultList();
entityManager.getTransaction().commit();
entityManager.close();
return Client.getCheckedList(clients);
}
}
通过spring以下列方式注入entityManagerFactory:
<bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource">
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
<property name="url" value="url" />
<property name="username" value="user" />
<property name="password" value="pw" />
</bean>
<bean
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
id="entityManagerFactory">
<property name="dataSource" ref="dataSource" />
</bean>
<context:component-scan base-package="com.theocean.dao">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Repository" />
</context:component-scan>
<bean class="org.springframework.orm.jpa.JpaTransactionManager"
id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="oceanClientDaoImpl" class="com.theocean.dao.OceanClientDaoImpl">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
当我第一次启动应用程序时,这一切都正常。应用程序服务器是Tomcat。但是,在应用程序运行一段时间后,对服务器的请求开始收到此错误:
> SEVERE: Servlet.service() for servlet [spring] in context with path [/OceanWebService] threw exception [Request processing failed; nested exception is javax.persistence.PersistenceException: org.hibernate.TransactionException: JDBC begin failed: ] with root cause
com.microsoft.sqlserver.jdbc.SQLServerException: SQL Server did not return a response. The connection has been closed.
at com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(SQLServerConnection.java:1667)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(SQLServerConnection.java:1654)
at com.microsoft.sqlserver.jdbc.TDSReader.readPacket(IOBuffer.java:4844)
at com.microsoft.sqlserver.jdbc.TDSCommand.startResponse(IOBuffer.java:6154)
at com.microsoft.sqlserver.jdbc.TDSCommand.startResponse(IOBuffer.java:6106)
at com.microsoft.sqlserver.jdbc.SQLServerConnection$1ConnectionCommand.doExecute(SQLServerConnection.java:1756)
at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:5696)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:1715)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectionCommand(SQLServerConnection.java:1761)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.setAutoCommit(SQLServerConnection.java:1901)
at sun.reflect.GeneratedMethodAccessor32.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.apache.tomcat.jdbc.pool.ProxyConnection.invoke(ProxyConnection.java:126)
at org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:99)
at org.apache.tomcat.jdbc.pool.DisposableConnectionFacade.invoke(DisposableConnectionFacade.java:58)
at com.sun.proxy.$Proxy32.setAutoCommit(Unknown Source)
at org.hibernate.transaction.JDBCTransaction.begin(JDBCTransaction.java:87)
at org.hibernate.impl.SessionImpl.beginTransaction(SessionImpl.java:1473)
at org.hibernate.ejb.TransactionImpl.begin(TransactionImpl.java:60)
at com.theocean.dao.OceanClientDaoImpl.loadClients(OceanClientDaoImpl.java:52)
at com.theocean.service.ExperienceClientService.loadClientsLight(ExperienceClientService.java:30)
at com.theocean.web.ExperienceController.loadClientsLight(ExperienceController.java:30)
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.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:436)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:424)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:669)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:574)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:947)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1009)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
SEVERE: Servlet.service() for servlet [spring] in context with path [/OceanWebService] threw exception [Request processing failed; nested exception is javax.persistence.PersistenceException: org.hibernate.TransactionException: JDBC begin failed: ] with root cause
com.microsoft.sqlserver.jdbc.SQLServerException: SQL Server did not return a response. The connection has been closed.
at com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(SQLServerConnection.java:1667)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.terminate(SQLServerConnection.java:1654)
at com.microsoft.sqlserver.jdbc.TDSReader.readPacket(IOBuffer.java:4844)
at com.microsoft.sqlserver.jdbc.TDSCommand.startResponse(IOBuffer.java:6154)
at com.microsoft.sqlserver.jdbc.TDSCommand.startResponse(IOBuffer.java:6106)
at com.microsoft.sqlserver.jdbc.SQLServerConnection$1ConnectionCommand.doExecute(SQLServerConnection.java:1756)
at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:5696)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:1715)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectionCommand(SQLServerConnection.java:1761)
at com.microsoft.sqlserver.jdbc.SQLServerConnection.setAutoCommit(SQLServerConnection.java:1901)
at sun.reflect.GeneratedMethodAccessor32.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.apache.tomcat.jdbc.pool.ProxyConnection.invoke(ProxyConnection.java:126)
at org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:99)
at org.apache.tomcat.jdbc.pool.DisposableConnectionFacade.invoke(DisposableConnectionFacade.java:58)
at com.sun.proxy.$Proxy32.setAutoCommit(Unknown Source)
at org.hibernate.transaction.JDBCTransaction.begin(JDBCTransaction.java:87)
at org.hibernate.impl.SessionImpl.beginTransaction(SessionImpl.java:1473)
at org.hibernate.ejb.TransactionImpl.begin(TransactionImpl.java:60)
at com.theocean.dao.OceanClientDaoImpl.loadClients(OceanClientDaoImpl.java:52)
at com.theocean.service.ExperienceClientService.loadClientsLight(ExperienceClientService.java:30)
at com.theocean.web.ExperienceController.loadClientsLight(ExperienceController.java:30)
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.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:436)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:424)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:669)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:574)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:947)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1009)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
因此,连接正在关闭。显然,无论是注入方法还是处理错误的方法等,实现都有问题。所以,问题是 - 这样做的正确方法是什么?如何避免连接关闭错误?非常感谢。
答案 0 :(得分:3)
我认为可能发生的事情是,当发生错误时,某些DAO会使数据库事务处于打开状态。
上面的示例DAO正在对数据库事务进行编程管理,但不处理回滚方案。这是DAO实现的一个例子:
MyService {
private EntityManagerFactory emf;
public void myMethod() {
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
MyDaoA myDaoA = new MyDaoA(em);
MyDaoB myDaoB = new MyDaoB(em);
try {
tx.begin();
myDaoA.doSomething();
myDaoB.doSomething();
tx.commit();
} catch(Exception e) {
tx.rollback();
}
}
}
所有执行程序化事务管理的DAO都应使用此模式,否则迟早不会回滚事务,这可能会导致问题。
实现DAO的更频繁,更不容易出错的方法是直接注入实体管理器:
MyService {
@PersistenceContext
private EntityManager em;
@Autowired
private MyDaoA myDaoA;
@Autowired
private MyDaoB myDaoB;
@Transactional
public void myMethod() {
myDaoA.doSomething();
myDaoB.doSomething();
}
}
应该为特殊情况保留注入EntityManagerFactory并进行手动事务管理,默认情况下使用@Transactional。
答案 1 :(得分:0)
我会说Connection pooling
存在问题,因此您可以使用c3p0
连接池库来解决问题,但您应该非常小心连接池属性。
实际上你可以做很多方法,我给你相同的代码供参考。它可能有所帮助。
第1步: persistence.xml
<!-- c3p0 properties -->
<!-- Determines how many connections at a time c3p0 will try to acquire when the pool is exhausted -->
<property name="hibernate.c3p0.acquire_increment" value="1"/>
<!-- If this is a number greater than 0,
c3p0 will test all idle, pooled but unchecked-out connections, every this number of seconds -->
<property name="hibernate.c3p0.idle_test_period" value="60"/>
<property name="hibernate.c3p0.max_size" value="20"/>
<property name="hibernate.c3p0.max_statements" value="50"/>
<property name="hibernate.c3p0.min_size" value="5"/>
<property name="hibernate.connection.provider_class" value="org.hibernate.connection.C3P0ConnectionProvider" />
第2步:然后我们使用以下属性在src / main / resources / META-INF下创建c3p0.properties
c3p0.testConnectionOnCheckout=true
c3p0.preferredTestQuery=SELECT 1;
第3步:您需要配置数据源
<bean id="myJdbcDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<!-- Connection properties -->
<property name="driverClass" value="$DS{database.class}" />
<property name="jdbcUrl" value="$DS{database.url}" />
<property name="user" value="$DS{database.username}" />
<property name="password" value="$DS{database.password}" />
<bean/>