如何在Oracle.sql.ARRAY类型中避免此死锁?

时间:2012-04-17 11:15:17

标签: oracle jdbc deadlock

当运行多个尝试写入数据库的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;
}

由于

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:1)

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

我们将DataSource包装为始终返回相同的连接,并解决了问题。

由于