Ejemplo n.º 1
0
 /**
  * Convenience method to close a PreparedStatement. If the statement is currently being used as a
  * batch, will register it for closing when executing the batch
  *
  * @param conn The Connection
  * @param ps The PreparedStatement
  * @throws SQLException if an error occurs closing the statement
  */
 public void closeStatement(ManagedConnection conn, PreparedStatement ps) throws SQLException {
   ConnectionStatementState state = getConnectionStatementState(conn);
   if (state != null && state.stmt == ps) {
     // Statement to be closed is the current batch, so register it for closing when it gets
     // processed
     state.closeStatementOnProcess = true;
   } else {
     try {
       if (NucleusLogger.DATASTORE.isDebugEnabled()) {
         NucleusLogger.DATASTORE.debug(LOCALISER.msg("052110", StringUtils.toJVMIDString(ps)));
       }
       ps.close();
     } catch (SQLException sqle) {
       // workaround for DBCP bug: even though PreparedStatement.close()
       // is defined as having no effect if already closed, DBCP
       // will throw SQLException
       if (!sqle.getMessage().equals("Already closed")) {
         throw sqle;
       }
     }
   }
 }
Ejemplo n.º 2
0
  /**
   * Method to execute a PreparedStatement update. Prints logging information about timings.
   *
   * @param conn The connection (required since the one on PreparedStatement is not always the same
   *     so we cant use it)
   * @param stmt The statement text
   * @param ps The Prepared Statement
   * @param processNow Whether to process this statement now (only applies if is batched)
   * @return The numer of rows affected (as per PreparedStatement.executeUpdate)
   * @throws SQLException Thrown if an error occurs
   */
  public int[] executeStatementUpdate(
      ExecutionContext ec,
      ManagedConnection conn,
      String stmt,
      PreparedStatement ps,
      boolean processNow)
      throws SQLException {
    ConnectionStatementState state = getConnectionStatementState(conn);
    if (state != null) {
      if (state.stmt == ps) {
        // Mark as processable
        if (NucleusLogger.DATASTORE_PERSIST.isDebugEnabled()) {
          NucleusLogger.DATASTORE_PERSIST.debug(
              LOCALISER.msg("052104", state.stmtText, "" + state.batchSize));
        }
        state.processable = true;
        state.stmt.addBatch();

        if (processNow) {
          // Process the batch now
          state.closeStatementOnProcess =
              false; // user method has requested execution so they can close it themselves now
          return processConnectionStatement(conn);
        } else {
          // Leave processing til later
          return null;
        }
      } else {
        // There is a waiting batch yet it is a different statement, so process that one now since
        // we need
        // our statement executing
        processConnectionStatement(conn);
      }
    }

    // Process the normal update statement
    long startTime = System.currentTimeMillis();
    if (NucleusLogger.DATASTORE_NATIVE.isDebugEnabled()) {
      if (ps instanceof ParamLoggingPreparedStatement) {
        NucleusLogger.DATASTORE_NATIVE.debug(
            ((ParamLoggingPreparedStatement) ps).getStatementWithParamsReplaced());
      } else {
        NucleusLogger.DATASTORE_NATIVE.debug(stmt);
      }
    }

    int ind = ps.executeUpdate();
    if (ec != null && ec.getStatistics() != null) {
      // Add to statistics
      ec.getStatistics().incrementNumWrites();
    }

    ps.clearBatch();
    if (NucleusLogger.DATASTORE_PERSIST.isDebugEnabled()) {
      NucleusLogger.DATASTORE_PERSIST.debug(
          LOCALISER.msg(
              "045001",
              "" + (System.currentTimeMillis() - startTime),
              "" + ind,
              StringUtils.toJVMIDString(ps)));
    }

    return new int[] {ind};
  }
Ejemplo n.º 3
0
  /**
   * Convenience method to create a new PreparedStatement for an update.
   *
   * @param conn The Connection to use for the statement
   * @param stmtText Statement text
   * @param batchable Whether this statement is batchable. Whether we will process the statement
   *     before any other statement
   * @param getGeneratedKeysFlag whether to request getGeneratedKeys for this statement
   * @return The PreparedStatement
   * @throws SQLException thrown if an error occurs creating the statement
   */
  public PreparedStatement getStatementForUpdate(
      ManagedConnection conn, String stmtText, boolean batchable, boolean getGeneratedKeysFlag)
      throws SQLException {
    Connection c = (Connection) conn.getConnection();
    if (supportsBatching) {
      ConnectionStatementState state = getConnectionStatementState(conn);
      if (state != null) {
        if (state.processable) {
          // We have a batchable statement in the queue that could be processed now if necessary
          if (!batchable) {
            // This new statement isnt batchable so process the existing one before returning our
            // new statement
            processConnectionStatement(conn);
          } else {
            // Check if we could batch onto this existing statement
            if (state.stmtText.equals(stmtText)) {
              // We can batch onto this statement
              if (maxBatchSize == -1 || state.batchSize < maxBatchSize) {
                state.batchSize++;
                state.processable =
                    false; // Have to wait til we process this part til processable again
                if (NucleusLogger.DATASTORE_PERSIST.isDebugEnabled()) {
                  NucleusLogger.DATASTORE_PERSIST.debug(
                      LOCALISER.msg("052100", stmtText, "" + state.batchSize));
                }
                return state.stmt;
              } else {
                // Reached max batch size so process it now and start again for this one
                if (NucleusLogger.DATASTORE_PERSIST.isDebugEnabled()) {
                  NucleusLogger.DATASTORE_PERSIST.debug(LOCALISER.msg("052101", state.stmtText));
                }
                processConnectionStatement(conn);
              }
            } else {
              // We cant batch using the current batch statement so process it first and return our
              // new one
              processConnectionStatement(conn);
            }
          }
        } else {
          if (batchable) {
            // The current statement is being batched so we cant batch this since cant process the
            // current statement now
            if (NucleusLogger.DATASTORE_PERSIST.isDebugEnabled()) {
              NucleusLogger.DATASTORE_PERSIST.debug(
                  LOCALISER.msg("052102", state.stmtText, stmtText));
            }
            batchable = false;
          }
        }
      }
    }

    PreparedStatement ps =
        (getGeneratedKeysFlag
            ? c.prepareStatement(stmtText, Statement.RETURN_GENERATED_KEYS)
            : c.prepareStatement(stmtText));
    ps
        .clearBatch(); // In case using statement caching and given one with batched statements left
                       // hanging (C3P0)
    if (!jdbcStatements) {
      // Wrap with our parameter logger
      ps = new ParamLoggingPreparedStatement(ps, stmtText);
      ((ParamLoggingPreparedStatement) ps).setParamsInAngleBrackets(paramValuesInBrackets);
    }
    if (NucleusLogger.DATASTORE.isDebugEnabled()) {
      NucleusLogger.DATASTORE.debug(LOCALISER.msg("052109", ps, StringUtils.toJVMIDString(c)));
    }

    if (batchable && supportsBatching) {
      // This statement is batchable so save it as the current batchable
      if (NucleusLogger.DATASTORE_PERSIST.isDebugEnabled()) {
        NucleusLogger.DATASTORE_PERSIST.debug(LOCALISER.msg("052103", stmtText));
      }
      ConnectionStatementState state = new ConnectionStatementState();
      state.stmt = ps;
      state.stmtText = stmtText;
      state.batchSize = 1;
      setConnectionStatementState(conn, state);
    }

    return ps;
  }