1

在运行多个试图写入数据库的 Java EE MDB 实例时,我们遇到了以下死锁情况:

[deadlocked thread] [ACTIVE] ExecuteThread: '7' for queue: 'weblogic.kernel.Default (self-tuning)':
Thread '[ACTIVE] ExecuteThread: '7' for queue: 'weblogic.kernel.Default (self-tuning)'' is waiting to acquire lock 'oracle.jdbc.driver.T4CConnection@90106ee' that is held by thread '[ACTIVE] ExecuteThread: '8' for queue: 'weblogic.kernel.Default (self-tuning)''

Stack trace:
oracle.sql.ARRAY.toBytes(ARRAY.java:673)
oracle.jdbc.driver.OraclePreparedStatement.setArrayCritical(OraclePreparedStatement.java:5985)
oracle.jdbc.driver.OraclePreparedStatement.setARRAYInternal(OraclePreparedStatement.java:5944)
oracle.jdbc.driver.OraclePreparedStatement.setObjectCritical(OraclePreparedStatement.java:8782)
oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:8278)
oracle.jdbc.driver.OraclePreparedStatement.setObject(OraclePreparedStatement.java:8868)
oracle.jdbc.driver.OraclePreparedStatementWrapper.setObject(OraclePreparedStatementWrapper.java:240)
weblogic.jdbc.wrapper.PreparedStatement.setObject(PreparedStatement.java:287)
org.springframework.jdbc.core.StatementCreatorUtils.setValue(StatementCreatorUtils.java:356)
org.springframework.jdbc.core.StatementCreatorUtils.setParameterValueInternal(StatementCreatorUtils.java:216)
org.springframework.jdbc.core.StatementCreatorUtils.setParameterValue(StatementCreatorUtils.java:127)
org.springframework.jdbc.core.PreparedStatementCreatorFactory$PreparedStatementCreatorImpl.setValues(PreparedStatementCreatorFactory.java:298)
org.springframework.jdbc.object.BatchSqlUpdate$1.setValues(BatchSqlUpdate.java:192)
org.springframework.jdbc.core.JdbcTemplate$4.doInPreparedStatement(JdbcTemplate.java:892)
org.springframework.jdbc.core.JdbcTemplate$4.doInPreparedStatement(JdbcTemplate.java:1)
org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:586)
org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:614)
org.springframework.jdbc.core.JdbcTemplate.batchUpdate(JdbcTemplate.java:883)
org.springframework.jdbc.object.BatchSqlUpdate.flush(BatchSqlUpdate.java:184)
com.csfb.fao.rds.rfi.common.dao.storedprocs.SaveEarlyExceptionBatchStoredProc.execute(SaveEarlyExceptionBatchStoredProc.java:93)
com.csfb.fao.rds.rfi.common.dao.EarlyExceptionDAOImpl.saveEarlyExceptionBatch(EarlyExceptionDAOImpl.java:34)
com.csfb.fao.rds.rfi.application.rulesengine.RulesEngine.saveEarlyExceptions(RulesEngine.java:302)
com.csfb.fao.rds.rfi.application.rulesengine.RulesEngine.executeRules(RulesEngine.java:209)
com.csfb.fao.rds.rfi.application.rulesengine.RulesEngine.onMessage(RulesEngine.java:97)
com.csfb.fao.rds.feeds.process.BaseWorkerMDB.onMessage(BaseWorkerMDB.java:518)
weblogic.ejb.container.internal.MDListener.execute(MDListener.java:466)
weblogic.ejb.container.internal.MDListener.transactionalOnMessage(MDListener.java:371)
weblogic.ejb.container.internal.MDListener.onMessage(MDListener.java:327)
weblogic.jms.client.JMSSession.onMessage(JMSSession.java:4547)
weblogic.jms.client.JMSSession.execute(JMSSession.java:4233)
weblogic.jms.client.JMSSession.executeMessage(JMSSession.java:3709)
weblogic.jms.client.JMSSession.access$000(JMSSession.java:114)
weblogic.jms.client.JMSSession$UseForRunnable.run(JMSSession.java:5058)
weblogic.work.SelfTuningWorkManagerImpl$WorkAdapterImpl.run(SelfTuningWorkManagerImpl.java:516)
weblogic.work.ExecuteThread.execute(ExecuteThread.java:201)
weblogic.work.ExecuteThread.run(ExecuteThread.java:173)

和...

[deadlocked thread] [ACTIVE] ExecuteThread: '8' for queue: 'weblogic.kernel.Default (self-tuning)':
Thread '[ACTIVE] ExecuteThread: '8' for queue: 'weblogic.kernel.Default (self-tuning)'' is waiting to acquire lock 'oracle.jdbc.driver.T4CConnection@b48b568' that is held by thread '[ACTIVE] ExecuteThread: '7' for queue: 'weblogic.kernel.Default (self-tuning)''

Stack trace:
oracle.sql.ARRAY.toBytes(ARRAY.java:673)
oracle.jdbc.driver.OraclePreparedStatement.setArrayCritical(OraclePreparedStatement.java:5985)
oracle.jdbc.driver.OraclePreparedStatement.setARRAYInternal(OraclePreparedStatement.java:5944)
oracle.jdbc.driver.OraclePreparedStatement.setObjectCritical(OraclePreparedStatement.java:8782)
oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:8278)
oracle.jdbc.driver.OraclePreparedStatement.setObject(OraclePreparedStatement.java:8868)
oracle.jdbc.driver.OraclePreparedStatementWrapper.setObject(OraclePreparedStatementWrapper.java:240)
weblogic.jdbc.wrapper.PreparedStatement.setObject(PreparedStatement.java:287)
org.springframework.jdbc.core.StatementCreatorUtils.setValue(StatementCreatorUtils.java:356)
org.springframework.jdbc.core.StatementCreatorUtils.setParameterValueInternal(StatementCreatorUtils.java:216)
org.springframework.jdbc.core.StatementCreatorUtils.setParameterValue(StatementCreatorUtils.java:127)
org.springframework.jdbc.core.PreparedStatementCreatorFactory$PreparedStatementCreatorImpl.setValues(PreparedStatementCreatorFactory.java:298)
org.springframework.jdbc.object.BatchSqlUpdate$1.setValues(BatchSqlUpdate.java:192)
org.springframework.jdbc.core.JdbcTemplate$4.doInPreparedStatement(JdbcTemplate.java:892)
org.springframework.jdbc.core.JdbcTemplate$4.doInPreparedStatement(JdbcTemplate.java:1)
org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:586)
org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:614)
org.springframework.jdbc.core.JdbcTemplate.batchUpdate(JdbcTemplate.java:883)
org.springframework.jdbc.object.BatchSqlUpdate.flush(BatchSqlUpdate.java:184)
com.csfb.fao.rds.rfi.common.dao.storedprocs.SaveEarlyExceptionBatchStoredProc.execute(SaveEarlyExceptionBatchStoredProc.java:93)
com.csfb.fao.rds.rfi.common.dao.EarlyExceptionDAOImpl.saveEarlyExceptionBatch(EarlyExceptionDAOImpl.java:34)
com.csfb.fao.rds.rfi.application.rulesengine.RulesEngine.saveEarlyExceptions(RulesEngine.java:302)
com.csfb.fao.rds.rfi.application.rulesengine.RulesEngine.executeRules(RulesEngine.java:209)
com.csfb.fao.rds.rfi.application.rulesengine.RulesEngine.onMessage(RulesEngine.java:97)
com.csfb.fao.rds.feeds.process.BaseWorkerMDB.onMessage(BaseWorkerMDB.java:518)
weblogic.ejb.container.internal.MDListener.execute(MDListener.java:466)
weblogic.ejb.container.internal.MDListener.transactionalOnMessage(MDListener.java:371)
weblogic.ejb.container.internal.MDListener.onMessage(MDListener.java:327)
weblogic.jms.client.JMSSession.onMessage(JMSSession.java:4547)
weblogic.jms.client.JMSSession.execute(JMSSession.java:4233)
weblogic.jms.client.JMSSession.executeMessage(JMSSession.java:3709)
weblogic.jms.client.JMSSession.access$000(JMSSession.java:114)
weblogic.jms.client.JMSSession$UseForRunnable.run(JMSSession.java:5058)
weblogic.work.SelfTuningWorkManagerImpl$WorkAdapterImpl.run(SelfTuningWorkManagerImpl.java:516)
weblogic.work.ExecuteThread.execute(ExecuteThread.java:201)
weblogic.work.ExecuteThread.run(ExecuteThread.java:173)

查看 ARRAY.toBytes() 方法:

  public byte[] toBytes()
    throws SQLException
  {
    synchronized (getInternalConnection())
    {
      return this.descriptor.toBytes(this, this.enableBuffering);
    }
  }

...,它在以下方法上同步(getInternalConnection() -> getPhysicalConnection()):

  oracle.jdbc.internal.OracleConnection getPhysicalConnection()
  {
    if (this.physicalConnection == null)
    {
      try
      {
        this.physicalConnection = ((oracle.jdbc.internal.OracleConnection)new OracleDriver().defaultConnection());
      }
      catch (SQLException localSQLException)
      {
      }

    }

    return this.physicalConnection;
  }

defaultConnection() 执行以下操作:

  public Connection defaultConnection()
    throws SQLException
  {
    if ((defaultConn == null) || (defaultConn.isClosed()))
    {
      synchronized (OracleDriver.class)
      {
        if ((defaultConn == null) || (defaultConn.isClosed()))
        {
          defaultConn = connect("jdbc:oracle:kprb:", new Properties());
        }
      }
    }

    return defaultConn;
  }

所以连接实例和 OracleDriver.class 对象上有同步......我看不出这怎么会死锁。为了达到需要在 OracleDriver.class 上锁定的地步,线程将已经在连接实例上拥有锁定......显然我错过了一些东西。

我们正在使用以下代码创建 ARRAY 类型:

public ARRAY getOracleLongArray(DataSource ds, List<Long> vals, String typeName)
        throws SQLException {
    oracle.jdbc.OracleConnection conn = (oracle.jdbc.OracleConnection) ds
            .getConnection();
    Object[] data = vals.toArray(new Object[0]);

    ARRAY mddArray = conn.createARRAY(typeName, data);
    conn.close(); // Close the extra connection made here.
    return mddArray;
}

谢谢

4

2 回答 2

2

看起来您正在与多个线程共享该连接(通过该defaultConnection()方法。不要那样做,确保一次只有一个线程使用一个连接。

于 2012-04-17T17:42:12.187 回答
1

马克得到了答案:我们使用的是连接池,但传递了对它的 DataSource 引用 - 每次我们创建一个 New ARRAY 对象时,它都会从 Datasource 获得一个不同的 Connection 对象(与实际 db 调用使用的对象不同),从而创建一个新的数据库连接。

我们包装了 DataSource 以始终返回相同的连接,它解决了这个问题。

谢谢

于 2012-04-18T12:51:17.457 回答