java - 带有 c3p0 的 spring JPA 在第一次请求时连接超时

标签 java spring spring-data-jpa connection-pooling c3p0

我们正在尝试使用 c3p0 实现连接池。问题是当我们的服务器长时间没有事务时,下一个事务的第一个事务就会出现连接超时问题。

异常堆栈跟踪:

     Could not open JPA EntityManager for transaction; nested exception is javax.persistence.Pers
                istenceException: org.hibernate.TransactionException: JDBC begin transaction failed:
                org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transacti
                on; nested exception is javax.persistence.PersistenceException: org.hibernate.TransactionException: JDBC begin t
                ransaction failed:
                        at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:431)
                        at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPla
                tformTransactionManager.java:373)
                        at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(Tra
                nsactionAspectSupport.java:427)
                        at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(Transact
                ionAspectSupport.java:276)
                        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java
                :96)
                        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:
                179)
                        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
                        at com.sun.proxy.$Proxy559.getMerchantById(Unknown Source)
                        at com.ag.controller.MerchantController.getMerchantById(MerchantController.java:1111)
                        at com.ag.controller.MerchantController.checkoutMerchant(MerchantController.java:226)
                        at sun.reflect.GeneratedMethodAccessor1766.invoke(Unknown Source)
                        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
                        at java.lang.reflect.Method.invoke(Method.java:498)
                        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:22
                1)
                        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod
                .java:137)
                        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(S
                ervletInvocableHandlerMethod.java:111)
                        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMetho
                d(RequestMappingHandlerAdapter.java:806)
                        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(Req
                uestMappingHandlerAdapter.java:729)
                        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodA
                dapter.java:85)
                        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
                        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
                        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
                        at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
                        at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
                        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
                        at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
                        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
                        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
                        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:
                85)
                        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
                        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
                        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
                        at com.ag.configuration.XSSFilter.doFilter(XSSFilter.java:27)
                        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
                        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.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.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500)
                        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456)
                        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
                        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
                        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
                        at java.lang.Thread.run(Thread.java:745)
                Caused by: javax.persistence.PersistenceException: org.hibernate.TransactionException: JDBC begin transaction fa
                iled:
                        at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1763)
                        at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1677)
                        at org.hibernate.jpa.spi.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.j
                ava:1771)
                        at org.hibernate.jpa.internal.TransactionImpl.begin(TransactionImpl.java:64)
                        at org.springframework.orm.jpa.vendor.HibernateJpaDialect.beginTransaction(HibernateJpaDialect.java:166)
                        at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:380)
                        ... 53 more
                Caused by: org.hibernate.TransactionException: JDBC begin transaction failed:
                        at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doBegin(JdbcTransaction.java:76)
                        at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.begin(AbstractTransactionImpl.java:162)
                        at org.hibernate.internal.SessionImpl.beginTransaction(SessionImpl.java:1435)
                        at org.hibernate.jpa.internal.TransactionImpl.begin(TransactionImpl.java:61)
                        ... 55 more
                Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from t
                he server was 54,078,423 milliseconds ago.  The last packet sent successfully to the server was 54,078,423 milli
                seconds ago. is longer than the server configured value of 'wait_timeout'. You should consider either expiring a
                nd/or testing connection validity before use in your application, increasing the server configured values for cl
                ient timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.
                        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
                        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
                        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
                        at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
                        at com.mysql.jdbc.Util.handleNewInstance(Util.java:400)
                        at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1038)
                        at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3621)
                        at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2429)
                        at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2594)
                        at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2541)
                        at com.mysql.jdbc.ConnectionImpl.setAutoCommit(ConnectionImpl.java:4882)
                        at com.mchange.v2.c3p0.impl.NewProxyConnection.setAutoCommit(NewProxyConnection.java:912)
                        at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doBegin(JdbcTransaction.java:72)
                        ... 58 more
                Caused by: java.net.SocketException: Connection timed out
                        at java.net.SocketOutputStream.socketWrite0(Native Method)
                        at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109)
                        at java.net.SocketOutputStream.write(SocketOutputStream.java:153)
                        at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
                        at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
                        at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3603)
                        ... 64 more

数据源配置:

     @Primary
        @Bean
        public DataSource agDataSource() {

        ComboPooledDataSource dataSource = new ComboPooledDataSource();
            try {
                dataSource.setDriverClass(Preconditions.checkNotNull(environment.getRequiredProperty("hibernate.connection.driver_class")));
            } catch (IllegalStateException | PropertyVetoException e) {
                e.printStackTrace();
            }
            dataSource.setJdbcUrl(Preconditions.checkNotNull(environment.getRequiredProperty("hibernate.connection.url")));
            dataSource.setUser(Preconditions.checkNotNull(environment.getRequiredProperty("hibernate.connection.username")));
            dataSource.setPassword(Preconditions.checkNotNull("hibernate.connection.password"));
        }



         @Primary
        @Bean(name="agEntityManagerFactory")
        public LocalContainerEntityManagerFactoryBean agEntityManagerFactory() throws ClassNotFoundException {
            final LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();

            entityManagerFactoryBean.setDataSource(agDataSource());
            entityManagerFactoryBean.setPackagesToScan(new String[] { "com.ag.entities" });
            entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);

            final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
            vendorAdapter.setShowSql(true);
            entityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter);
            //entityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter);
            entityManagerFactoryBean.setJpaProperties(hibernateProperties());

            entityManagerFactoryBean.afterPropertiesSet();
            entityManagerFactoryBean.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver());

            return entityManagerFactoryBean;
        }

        @Primary
        @Bean(name = "agTransactionManager")
        public PlatformTransactionManager agTransactionManager() {
            final JpaTransactionManager transactionManager = new JpaTransactionManager();
            try {
                transactionManager.setEntityManagerFactory(agEntityManagerFactory().getObject());
                transactionManager.setDataSource(agDataSource());
                transactionManager.setJpaDialect(new HibernateJpaDialect());
                //transactionManager.setNestedTransactionAllowed(true);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            return transactionManager;
        }

最佳答案

我可以通过在数据源对象本身上设置连接池属性来解决该问题。我认为 hibernate 属性无法反射(reflect)池设置。我可以通过在 mysql 的 my.ini 文件中设置 wait_timeout=60、interactive_timeout=60(即 1 分钟)来在开发环境中复制该问题。然后在服务器启动后,我尝试了第一个事务,等待了 1 分钟,然后尝试了失败的 txn。然后我启用了查询日志(通过在 my.ini 中设置另外两个属性:

general_log = 1

general_log_file = "C:/xampp/mysql/data/mysql.log"

我启用了上述设置来检查我的select 1验证查询是否正在执行。我尝试了数据源对象本身的池设置,它开始工作。查询日志还显示每 hibernate.c3p0.idle_test_period 秒执行一次 selec 1。

@Primary
        @Bean
        public DataSource agDataSource() {

        ComboPooledDataSource dataSource = new ComboPooledDataSource();
            try {
                dataSource.setDriverClass(environment.getRequiredProperty("hibernate.connection.driver_class"));
            } catch (IllegalStateException | PropertyVetoException e) {
                e.printStackTrace();
            }
            dataSource.setJdbcUrl(environment.getRequiredProperty("hibernate.connection.url"));
            dataSource.setUser(environment.getRequiredProperty("hibernate.connection.username"));
            dataSource.setPassword(environment.getRequiredProperty("hibernate.connection.password"));

             dataSource.setMaxPoolSize(Integer.parseInt(environment.getRequiredProperty("hibernate.c3p0.max_size")));
            dataSource.setMinPoolSize(Integer.parseInt(environment.getRequiredProperty("hibernate.c3p0.min_size")));
            dataSource.setMaxIdleTime(Integer.parseInt(environment.getRequiredProperty("hibernate.c3p0.timeout")));
            dataSource.setMaxStatements(Integer.parseInt(environment.getRequiredProperty("hibernate.c3p0.max_statements")));
            dataSource.setIdleConnectionTestPeriod(Integer.parseInt(environment.getRequiredProperty("hibernate.c3p0.idle_test_period")));
            dataSource.setAcquireIncrement(Integer.parseInt(environment.getRequiredProperty("hibernate.c3p0.acquire_increment")));
            dataSource.setPreferredTestQuery(environment.getRequiredProperty("hibernate.c3p0.preferredTestQuery"));
            dataSource.setTestConnectionOnCheckin(true);
            dataSource.setTestConnectionOnCheckout(true);

            return dataSource;
        }

现在一切正常了。快乐的。我发布了答案以及验证我的设置的步骤,以便对其他人有所帮助。

关于java - 带有 c3p0 的 spring JPA 在第一次请求时连接超时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40671930/

相关文章:

java - 在运行时在 java(android) 中存储敏感数据

java - 如何避免在 Spring Integration @ServiceActivator 方法中将 header 从输入复制到输出

java - Spring 文件上传 - 'Required request part is not present'

java - 我如何在 cucumber Stepdefs 中模拟第三方?

mysql - 用户 '' @'localhost' 的访问被拒绝(使用密码 : NO) spring-boot

java - 使用 HSSFWorkbook 将 Jtable 导出到 Excelsheet

java - 如何在Java Gradle项目中包括对库的引用

java - 设置自定义字段名称和代码

java - 如何使用代理解析从 SimpleJpaRepository<T,ID> 对象中获取存储库接口(interface)对象

java - Spring 数据 JPA : Creating Specification Query Fetch Joins