0

我在我的一个生产环境中面临这个问题。它经常发生但并不总是在应用程序的同一部分发生,它非常随机。

部署在此环境中的应用程序与部署在不同机器上的其他应用程序非常相似,它们使用相同的技术和关闭设置,但错误仅发生在此环境中,因此很难找出问题所在。

我必须说这些错误最近开始出现,因为有几个更新更改:

应用程序从 Windows 迁移到 Linux

PostgresSQL 8.2 到 9.2

雄猫 5 到 雄猫 6

所有这些更改也已在其他未遇到任何问题的已部署应用程序上完成。

应用程序使用的技术是:

休眠 2.1.6

PostgreSQL 9.2

雄猫 6.0.35

context.xml 中的配置是:

<Resource name="jdbc/psa" auth="Container" type="javax.sql.DataSource"
        driverClassName="org.postgresql.Driver" url="jdbc:postgresql://localhost:5432/psa?compatible=7.4"
        username="xxx" password="xxx" maxActive="100" maxIdle="30"
        maxWait="10000" factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory"
        defaultAutoCommit="false" removeAbandoned="true"
        removeAbandonedTimeout="60" logAbandoned="true" validationQuery="select 1"
        testOnBorrow="true" testOnReturn="true" testWhileIdle="true"
        timeBetweenEvictionRunsMillis="300000"/>

请注意,驱逐是活跃的,只是试图解决问题,但没有结果。

接下来是一个典型问题的流程:

1.- 打开一个新的 Hibernate 会话

2.- 我在查询之前检查此会话是否已打开并连接

3.-在日志上看到打开的会话有效后,产生了异常

- 添加

其中一个错误的完整堆栈跟踪如下:

29 03 2013 10:00:00 INFO EasyApScheduler_Worker-8 com.psa.accounting.eureca.logic.EurecaNLAccountingLogic - -- Process EURECA_NL starts
    29 03 2013 10:00:00 INFO EasyApScheduler_Worker-2 com.psa.accounting.eureca.logic.EurecaSCAccountingLogic - -- Process EURECA_SC starts
    29 03 2013 10:00:00 DEBUG EasyApScheduler_Worker-2 com.xeridia.persistence.ServiceLocator - Session opened: net.sf.hibernate.impl.SessionImpl@22880d66. Opened: true, Connected: true
    29 03 2013 10:00:00 DEBUG EasyApScheduler_Worker-2 com.xeridia.persistence.ServiceLocator - [getConnection]|16|Thread[EasyApScheduler_Worker-2,4,main]|
    29 03 2013 10:00:00 DEBUG EasyApScheduler_Worker-2 com.xeridia.persistence.ServiceLocator - [getConnection]|16|Thread[EasyApScheduler_Worker-2,4,main]|com.easyap.invoice.persistence.InvoiceDAOHibernate.<init>(InvoiceDAOHibernate.java:364)
    29 03 2013 10:00:00 ERROR EasyApScheduler_Worker-8 net.sf.hibernate.util.JDBCExceptionReporter - Connection org.postgresql.jdbc3g.Jdbc3gConnection@1b0ca3f7 is closed.
    29 03 2013 10:00:00 DEBUG EasyApScheduler_Worker-2 com.xeridia.persistence.ServiceLocator - [getConnection]|16|Thread[EasyApScheduler_Worker-2,4,main]|com.psa.invoice.persistence.PSAInvoiceDAOHibernate.<init>(PSAInvoiceDAOHibernate.java:52)
    29 03 2013 10:00:00 ERROR EasyApScheduler_Worker-8 net.sf.hibernate.util.JDBCExceptionReporter - Connection org.postgresql.jdbc3g.Jdbc3gConnection@1b0ca3f7 is closed.
    29 03 2013 10:00:00 ERROR EasyApScheduler_Worker-8 net.sf.hibernate.util.JDBCExceptionReporter - Could not execute query
    java.sql.SQLException: Connection org.postgresql.jdbc3g.Jdbc3gConnection@1b0ca3f7 is closed.
        at org.apache.tomcat.dbcp.dbcp.DelegatingConnection.checkOpen(DelegatingConnection.java:398)
        at org.apache.tomcat.dbcp.dbcp.DelegatingConnection.prepareStatement(DelegatingConnection.java:279)
        at org.apache.tomcat.dbcp.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.prepareStatement(PoolingDataSource.java:313)
        at net.sf.hibernate.impl.BatcherImpl.getPreparedStatement(BatcherImpl.java:257)
        at net.sf.hibernate.impl.BatcherImpl.getPreparedStatement(BatcherImpl.java:232)
        at net.sf.hibernate.impl.BatcherImpl.prepareQueryStatement(BatcherImpl.java:65)
        at net.sf.hibernate.loader.Loader.prepareQueryStatement(Loader.java:779)
        at net.sf.hibernate.loader.Loader.doQuery(Loader.java:265)
        at net.sf.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:133)
        at net.sf.hibernate.loader.Loader.doList(Loader.java:1033)
        at net.sf.hibernate.loader.Loader.list(Loader.java:1024)
        at net.sf.hibernate.hql.QueryTranslator.list(QueryTranslator.java:854)
        at net.sf.hibernate.impl.SessionImpl.find(SessionImpl.java:1544)
        at net.sf.hibernate.impl.QueryImpl.list(QueryImpl.java:39)
        at com.xeridia.persistence.BaseDAOHibernate.findByQuery(BaseDAOHibernate.java:312)
        at com.xeridia.persistence.BaseDAOHibernate.findByQuery(BaseDAOHibernate.java:291)
        at com.psa.invoice.persistence.PSAInvoiceDAOHibernate.getAccountingInvoicesWithNoProblem(PSAInvoiceDAOHibernate.java:215)
        at com.psa.accounting.eureca.logic.EurecaNLAccountingLogic.getAccountingDataFromDB(EurecaNLAccountingLogic.java:469)
        at com.psa.accounting.eureca.logic.EurecaNLAccountingLogic.process(EurecaNLAccountingLogic.java:207)
        at com.psa.accounting.eureca.scheduler.CronEurecaNLAccounting.execute(CronEurecaNLAccounting.java:91)
        at org.quartz.core.JobRunShell.run(JobRunShell.java:203)
        at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:520)

管理所有 Hibernate 会话的类是一个名为 ServiceLocator 的类。此类的方法 getConnection() 返回一个新连接,其代码如下:

synchronized (session) {
                s = (Session) session.get();
                if ((s == null)||(!s.isOpen())) {
                    s = null;
                    s = getSessionFactory().openSession();
                    if (s != null) {
                        log.debug("Session opened: " + s + ". Opened: " + s.isOpen() +
                                ", Connected: " + s.isConnected());
                        printThreadDataForClosedConnections("[getConnection]");
                    }
                    session.set(s);
                }
                if (!s.isConnected()) {
                    s.reconnect();
                    log.debug("Session reconnected: " + s + ". Opened: " + s.isOpen() +
                            ", Connected: " + s.isConnected());
                    printThreadDataForClosedConnections("[getConnection]");
                }
            }

对象“会话”声明为:

public static final ThreadLocal session = new ThreadLocal();

为不同的线程获取不同的会话,因此关闭线程之间的会话不应该存在问题。

您在上面的堆栈跟踪中可以看到,EasyApScheduler_Worker-2 获得了一个新连接,if ((s == null)||(!s.isOpen())) {但 EasyApScheduler_Worker-8 没有,这意味着它的“会话”对象存在并且打开或无法获得连接,对应于第一个错误的踪迹29 03 2013 10:00:00 ERROR EasyApScheduler_Worker-8 net.sf.hibernate.util.JDBCExceptionReporter - Connection org.postgresql.jdbc3g.Jdbc3gConnection@1b0ca3f7 is closed.

我不知道问题是来自 Hibernate、Postgres 还是 Tomcat。我在谷歌上几乎没有发现这个错误,所以我希望你能帮帮我。

请询问您需要的任何额外信息或设置以提供帮助。

提前致谢。

4

1 回答 1

0

我已经解决了这个问题。

这是石英线程的问题。默认情况下,Quartz 管理一个线程池,这些线程池在不同作业的执行之间被重用。我的类ServiceLocator,负责打开和关闭连接,是基于ThreadLocal对象的。似乎我的一项计划作业没有正确关闭其连接,之后,在与该作业相同的线程上执行的所有作业都导致了错误。

我不知道什么是有问题的工作,我最终所做的是将 Quartz 的默认连接池更改为自定义连接池,这样我为每个作业执行创建一个新线程,而不是共享某个所有作业的线程数量。

这是我编写的 Quartz 自定义线程池,以防它对某人有用:

public class SimpleNoThreadPooling implements ThreadPool {

    public int getPoolSize() {
        return 0;
    }


    public Log getLog() {
        return LogFactory.getLog(SimpleNoThreadPooling.class);
    }

    public void initialize() throws SchedulerConfigException { }

    class WorkerThread extends Thread {

        private Runnable runnable = null;

        /**
         * <p>
         * Create a worker thread, start it, execute the runnable and terminate
         * the thread (one time execution).
         * </p>
         */
        WorkerThread(Runnable runnable) {
            this.runnable = runnable;
            start();
        }

        public void run() {
            if (runnable != null) {
                try {
                    runnable.run();
                } catch (Exception exceptionInRunnable) {
                    try {
                        getLog().error("Error while executing the Runnable: ",
                            exceptionInRunnable);
                    } catch(Exception e) {  
                        // ignore to help with a tomcat glitch
                    }
                }
            }
        }
    }

    public boolean runInThread(Runnable runnable) {
        new WorkerThread(runnable);
        return true;
    }

    public void shutdown(boolean waitForJobsToComplete) { }

}
于 2013-04-10T12:25:07.777 回答