/** * Method to return a string form of this object for convenience debug. * * @return The String form */ public String toString() { return StringUtils.toJVMIDString(this) + " [conn=" + StringUtils.toJVMIDString(conn) + ", commitOnRelease=" + commitOnRelease + ", closeOnRelease=" + closeOnRelease + ", closeOnTxnEnd=" + closeAfterTransactionEnd() + "]"; }
public String toString() { return "StateManager[pc=" + StringUtils.toJVMIDString(getObject()) + ", lifecycle=" + myLC + "]"; }
/** * Convenience method to create a new PreparedStatement for a query. * * @param conn The Connection to use for the statement * @param stmtText Statement text * @param resultSetType Type of result set * @param resultSetConcurrency Concurrency for the result set * @return The PreparedStatement * @throws SQLException thrown if an error occurs creating the statement */ public PreparedStatement getStatementForQuery( ManagedConnection conn, String stmtText, String resultSetType, String resultSetConcurrency) throws SQLException { Connection c = (Connection) conn.getConnection(); if (supportsBatching) { // Check for a waiting batched statement that is ready for processing ConnectionStatementState state = getConnectionStatementState(conn); if (state != null && state.processable) { // Process the batch statement before returning our new query statement processConnectionStatement(conn); } } // Create a new PreparedStatement for this query PreparedStatement ps = null; if (resultSetType != null || resultSetConcurrency != null) { int rsTypeValue = ResultSet.TYPE_FORWARD_ONLY; if (resultSetType != null) { if (resultSetType.equals("scroll-sensitive")) { rsTypeValue = ResultSet.TYPE_SCROLL_SENSITIVE; } else if (resultSetType.equals("scroll-insensitive")) { rsTypeValue = ResultSet.TYPE_SCROLL_INSENSITIVE; } } int rsConcurrencyValue = ResultSet.CONCUR_READ_ONLY; if (resultSetConcurrency != null && resultSetConcurrency.equals("updateable")) { rsConcurrencyValue = ResultSet.CONCUR_UPDATABLE; } ps = c.prepareStatement(stmtText, rsTypeValue, rsConcurrencyValue); ps .clearBatch(); // In case using statement caching and given one with batched statements // left hanging (C3P0) } else { ps = c.prepareStatement(stmtText); ps .clearBatch(); // In case using statement caching and given one with batched statements // left hanging (C3P0) } if (queryTimeout > 0) { // Apply any query timeout ps.setQueryTimeout(queryTimeout / 1000); // queryTimeout is in milliseconds } if (NucleusLogger.DATASTORE.isDebugEnabled()) { NucleusLogger.DATASTORE.debug(LOCALISER.msg("052110", StringUtils.toJVMIDString(ps))); } if (!jdbcStatements) { // Wrap with our parameter logger ps = new ParamLoggingPreparedStatement(ps, stmtText); ((ParamLoggingPreparedStatement) ps).setParamsInAngleBrackets(paramValuesInBrackets); } return ps; }
public String toString() { return "StmtState : stmt=" + StringUtils.toJVMIDString(stmt) + " sql=" + stmtText + " batch=" + batchSize + " closeOnProcess=" + closeStatementOnProcess; }
/** * Convenience method to retrieve field values from an L2 cached object if they are loaded in that * object. If the object is not in the L2 cache then just returns, and similarly if the required * fields aren't available. * * @param fieldNumbers Numbers of fields to load from the L2 cache * @return The fields that couldn't be loaded */ protected int[] loadFieldsFromLevel2Cache(int[] fieldNumbers) { // Only continue if there are fields, and not being deleted/flushed etc if (fieldNumbers == null || fieldNumbers.length == 0 || myEC.isFlushing() || myLC.isDeleted() || isDeleting() || getExecutionContext().getTransaction().isCommitting()) { return fieldNumbers; } // TODO Drop this check when we're confident that this doesn't affect some use-cases if (!myEC.getNucleusContext() .getConfiguration() .getBooleanProperty(PropertyNames.PROPERTY_CACHE_L2_LOADFIELDS, true)) { return fieldNumbers; } Level2Cache l2cache = myEC.getNucleusContext().getLevel2Cache(); if (l2cache != null && myEC.getNucleusContext().isClassCacheable(cmd)) { CachedPC<T> cachedPC = l2cache.get(myID); if (cachedPC != null) { int[] cacheFieldsToLoad = ClassUtils.getFlagsSetTo(cachedPC.getLoadedFields(), fieldNumbers, true); if (cacheFieldsToLoad != null && cacheFieldsToLoad.length > 0) { if (NucleusLogger.CACHE.isDebugEnabled()) { NucleusLogger.CACHE.debug( Localiser.msg( "026034", StringUtils.toJVMIDString(getObject()), myID, StringUtils.intArrayToString(cacheFieldsToLoad))); } L2CacheRetrieveFieldManager l2RetFM = new L2CacheRetrieveFieldManager(this, cachedPC); this.replaceFields(cacheFieldsToLoad, l2RetFM); int[] fieldsNotLoaded = l2RetFM.getFieldsNotLoaded(); if (fieldsNotLoaded != null) { for (int i = 0; i < fieldsNotLoaded.length; i++) { loadedFields[fieldsNotLoaded[i]] = false; } } } } } return ClassUtils.getFlagsSetTo(loadedFields, fieldNumbers, false); }
/** * Convenience method to update a Level2 cached version of this object if cacheable and has not * been modified during this transaction. * * @param fieldNumbers Numbers of fields to update in L2 cached object */ protected void updateLevel2CacheForFields(int[] fieldNumbers) { String updateMode = (String) myEC.getProperty(PropertyNames.PROPERTY_CACHE_L2_UPDATE_MODE); if (updateMode != null && updateMode.equalsIgnoreCase("commit-only")) { return; } if (fieldNumbers == null || fieldNumbers.length == 0) { return; } Level2Cache l2cache = myEC.getNucleusContext().getLevel2Cache(); if (l2cache != null && myEC.getNucleusContext().isClassCacheable(cmd) && !myEC.isObjectModifiedInTransaction(myID)) { CachedPC<T> cachedPC = l2cache.get(myID); if (cachedPC != null) { // This originally just updated the L2 cache for fields where the L2 cache didn't have a // value for that field, like this /* int[] cacheFieldsToLoad = ClassUtils.getFlagsSetTo(cachedPC.getLoadedFields(), fieldNumbers, false); if (cacheFieldsToLoad == null || cacheFieldsToLoad.length == 0) { return; } */ int[] cacheFieldsToLoad = fieldNumbers; CachedPC copyCachedPC = cachedPC.getCopy(); if (NucleusLogger.CACHE.isDebugEnabled()) { NucleusLogger.CACHE.debug( Localiser.msg( "026033", StringUtils.toJVMIDString(getObject()), myID, StringUtils.intArrayToString(cacheFieldsToLoad))); } provideFields(cacheFieldsToLoad, new L2CachePopulateFieldManager(this, copyCachedPC)); // Replace the current L2 cached object with this one myEC.getNucleusContext().getLevel2Cache().put(getInternalObjectId(), copyCachedPC); } } }
/** * Method to execute a PreparedStatement (using PreparedStatement.execute()). Prints logging * information about timings. * * @param ec Execution Context * @param conn The connection (required since the one on PreparedStatement is not always the same * so we can't use it) * @param stmt The statement text * @param ps The Prepared Statement * @return The numer of rows affected (as per PreparedStatement.execute) * @throws SQLException Thrown if an error occurs */ public boolean executeStatement( ExecutionContext ec, ManagedConnection conn, String stmt, PreparedStatement ps) throws SQLException { if (supportsBatching) { // Check for a waiting batched statement that is ready for processing ConnectionStatementState state = getConnectionStatementState(conn); if (state != null && state.processable) { // Process the batch statement before returning our new query statement processConnectionStatement(conn); } } // Process the normal execute 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); } } boolean flag = ps.execute(); 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( "045002", "" + (System.currentTimeMillis() - startTime), StringUtils.toJVMIDString(ps))); } return flag; }
/** * 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; } } } }
/** * Convenience method to process the currently waiting statement for the passed Connection. Only * processes the statement if it is in processable state. * * @param conn The connection * @return The return codes from the statement batch * @throws SQLException if an error occurs processing the batch */ protected int[] processConnectionStatement(ManagedConnection conn) throws SQLException { ConnectionStatementState state = getConnectionStatementState(conn); if (state == null || !state.processable) { return null; } long startTime = System.currentTimeMillis(); if (NucleusLogger.DATASTORE_NATIVE.isDebugEnabled()) { if (state.stmt instanceof ParamLoggingPreparedStatement) { NucleusLogger.DATASTORE_NATIVE.debug( ((ParamLoggingPreparedStatement) state.stmt).getStatementWithParamsReplaced()); } else { NucleusLogger.DATASTORE_NATIVE.debug(state.stmtText); } } int[] ind = state.stmt.executeBatch(); state.stmt.clearBatch(); if (NucleusLogger.DATASTORE.isDebugEnabled()) { NucleusLogger.DATASTORE.debug( LOCALISER.msg( "045001", "" + (System.currentTimeMillis() - startTime), StringUtils.intArrayToString(ind), StringUtils.toJVMIDString(state.stmt))); } // Remove the current connection statement removeConnectionStatementState(conn); // Close the statement if it is registered for closing after processing if (state.closeStatementOnProcess) { state.stmt.close(); } return ind; }
public String getObjectAsPrintable() { return StringUtils.toJVMIDString(getObject()); }
/** * 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}; }
/** * 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; }