Example usage for java.sql Connection rollback

List of usage examples for java.sql Connection rollback

Introduction

In this page you can find the example usage for java.sql Connection rollback.

Prototype

void rollback(Savepoint savepoint) throws SQLException;

Source Link

Document

Undoes all changes made after the given Savepoint object was set.

Usage

From source file:com.gtwm.pb.model.manageSchema.DatabaseDefn.java

/**
 * Updates the definition of a view within the DB. This method will not work
 * if the number of columns within the view are being changed.
 *///from w  w w . j ava  2 s . com
private boolean updateViewDbActionWithCreateOrReplace(Connection conn, BaseReportInfo report,
        boolean viewExists)
        throws SQLException, CantDoThatException, CodingErrorException, ObjectNotFoundException {
    String SQLCode = "CREATE OR REPLACE VIEW " + report.getInternalReportName() + " AS ("
            + report.getSQLForDetail() + ")";
    boolean createOrReplaceWorked = true;
    Savepoint savepoint = null;
    PreparedStatement statement = null;
    try {
        savepoint = conn.setSavepoint("createOrReplaceSavepoint");
        statement = conn.prepareStatement(SQLCode);
        statement.execute();
        statement.close();
    } catch (SQLException sqlex) {
        if (viewExists) {
            createOrReplaceWorked = false;
            conn.rollback(savepoint);
        } else {
            // if view didn't exist already, the error must be more serious
            // than just the CREATE OR REPLACE not working
            // logger.error("Requested change to report " +
            // report.getReportName()
            // + " would break view. Error = " + sqlex);
            // logger.error("SQL = " + report.getSQLForDetail());
            throw new SQLException("The requested change would cause an error in the report: "
                    + sqlex.getMessage() + ". SQL = " + statement, sqlex.getSQLState(), sqlex);
        }
    }
    return createOrReplaceWorked;
}

From source file:com.gtwm.pb.model.manageSchema.DatabaseDefn.java

/**
 * Updates the definition of a view within the DB. This method should only
 * be used if updateViewDbActionWithCreateOrReplace fails. Drops the view
 * and recreates it.// www .j a  v  a  2 s .  c o m
 */
private boolean updateViewDbActionWithDropAndCreate(Connection conn, BaseReportInfo report)
        throws SQLException, CantDoThatException, CodingErrorException, ObjectNotFoundException {
    String CreateViewSQL = "CREATE VIEW " + report.getInternalReportName() + " AS (" + report.getSQLForDetail()
            + ")";
    boolean dropAndCreateWorked = true;
    Savepoint savepoint = null;
    try {
        savepoint = conn.setSavepoint("dropAndCreateSavepoint");
        PreparedStatement dropViewStatement = conn
                .prepareStatement("DROP VIEW " + report.getInternalReportName());
        dropViewStatement.execute();
        dropViewStatement.close();
        PreparedStatement statement = conn.prepareStatement(CreateViewSQL);
        statement.execute();
        statement.close();
    } catch (SQLException sqlex) {
        conn.rollback(savepoint);
        dropAndCreateWorked = false;
    }
    return dropAndCreateWorked;
}

From source file:com.gtwm.pb.model.manageSchema.DatabaseDefn.java

public void addCalculationToReport(HttpServletRequest request, Connection conn, SimpleReportInfo report,
        ReportCalcFieldInfo calculationField) throws SQLException, DisallowedException,
        InconsistentStateException, CantDoThatException, CodingErrorException, ObjectNotFoundException {
    if (!(this.authManager.getAuthenticator().loggedInUserAllowedTo(request, PrivilegeType.MANAGE_TABLE,
            report.getParentTable()))) {
        throw new DisallowedException(this.authManager.getLoggedInUser(request), PrivilegeType.MANAGE_TABLE,
                report.getParentTable());
    }/*from   w ww . jav  a2s  .c o  m*/
    HibernateUtil.activateObject(report);
    Savepoint savepoint = null;
    report.addCalculation(calculationField);
    savepoint = conn.setSavepoint("addCalculationSavepoint");
    try {
        this.updateViewDbAction(conn, report, request);
    } catch (SQLException sqlex) {
        // detect aggregate functions
        if (sqlex.getMessage().contains("must appear in the GROUP BY clause")
                || sqlex.getMessage().contains("aggregates not allowed in GROUP BY clause")) {
            conn.rollback(savepoint);
            calculationField.setAggregateFunction(true);
            this.updateViewDbAction(conn, report, request);
        } else {
            throw sqlex;
        }
    }
    UsageLogger usageLogger = new UsageLogger(this.relationalDataSource);
    AppUserInfo user = this.authManager.getUserByUserName(request, request.getRemoteUser());
    usageLogger.logReportSchemaChange(user, report, AppAction.ADD_CALCULATION_TO_REPORT,
            "calculation name: " + calculationField.getFieldName());
    UsageLogger.startLoggingThread(usageLogger);
}

From source file:com.gtwm.pb.model.manageSchema.DatabaseDefn.java

public void updateCalculationInReport(HttpServletRequest request, Connection conn, SimpleReportInfo report,
        ReportCalcFieldInfo calculationField, String calculationName, String calculationDefn,
        DatabaseFieldType dbFieldType, boolean isReportHidden) throws DisallowedException, SQLException,
        ObjectNotFoundException, CantDoThatException, CodingErrorException {
    if (!(this.authManager.getAuthenticator().loggedInUserAllowedTo(request, PrivilegeType.MANAGE_TABLE,
            report.getParentTable()))) {
        throw new DisallowedException(this.authManager.getLoggedInUser(request), PrivilegeType.MANAGE_TABLE,
                report.getParentTable());
    }/*w  w w.  j a  v  a  2 s  . c om*/
    HibernateUtil.activateObject(report);
    Savepoint savepoint = null;
    boolean definitionUpdate = false;
    if (!(calculationDefn.toLowerCase().equals(calculationField.getCalculationDefinition()))
            || !(dbFieldType.equals(calculationField.getDbType()))) {
        Map<TableInfo, Set<BaseReportInfo>> availableDataStores = this.getViewableDataStores(request);
        ((ReportCalcFieldDefn) calculationField).updateCalculationDefinition(calculationDefn, dbFieldType,
                availableDataStores);
        definitionUpdate = true;
    } else {
        ((ReportCalcFieldDefn) calculationField).setBaseFieldName(calculationName);
        calculationField.setReportHidden(isReportHidden);
    }
    if (definitionUpdate) {
        savepoint = conn.setSavepoint("updateCalculationSavepoint");
        try {
            this.updateViewDbAction(conn, report, request);
        } catch (SQLException sqlex) {
            // detect aggregate functions
            if (sqlex.getMessage().contains("must appear in the GROUP BY clause")
                    || sqlex.getMessage().contains("aggregates not allowed in GROUP BY clause")) {
                conn.rollback(savepoint);
                calculationField.setAggregateFunction(true);
                this.updateViewDbAction(conn, report, request);
            } else {
                throw sqlex;
            }
        }
    }
    UsageLogger usageLogger = new UsageLogger(this.relationalDataSource);
    AppUserInfo user = this.authManager.getUserByUserName(request, request.getRemoteUser());
    usageLogger.logReportSchemaChange(user, report, AppAction.UPDATE_CALCULATION_IN_REPORT,
            "calculation name: " + calculationField.getFieldName());
    UsageLogger.startLoggingThread(usageLogger);
}

From source file:com.gtwm.pb.model.manageSchema.DatabaseDefn.java

/**
 * Updates the definition of a view within the DB. This method should only
 * be used if updateViewDbActionWithDropAndCreate and
 * updateViewDbActionWithCreateOrReplace fails. Drops any dependent views so
 * that 'report' can be updated. Once report has been updated, all dependent
 * views are recreated.//from  w w  w.j  a  v  a2s.c  om
 */
private void updateViewDbActionWithDropAndCreateDependencies(Connection conn, BaseReportInfo report,
        HttpServletRequest request)
        throws SQLException, ObjectNotFoundException, CodingErrorException, CantDoThatException {
    Savepoint savepoint = null;
    PreparedStatement statement = null;
    try {
        savepoint = conn.setSavepoint("dropAndCreateDependenciesSavepoint");
        Map<String, List<String>> reportDependencyMap = new HashMap<String, List<String>>();
        this.fillViewDependencyMap(conn, report.getInternalReportName(), reportDependencyMap, true);
        // Remove reports...
        List<String> deletedReports = new ArrayList<String>();
        while (deletedReports.size() < reportDependencyMap.size()) {
            for (String reportInternalName : reportDependencyMap.keySet()) {
                if (!deletedReports.contains(reportInternalName)) {
                    boolean cannotDelete = false;
                    for (String dependentReportInternalName : reportDependencyMap.get(reportInternalName)) {
                        if (!deletedReports.contains(dependentReportInternalName)) {
                            cannotDelete = true;
                        }
                    }
                    if (!cannotDelete) {
                        PreparedStatement dropViewStatement = conn
                                .prepareStatement("DROP VIEW " + reportInternalName);
                        dropViewStatement.execute();
                        dropViewStatement.close();
                        deletedReports.add(reportInternalName);
                    }
                }
            }
        }
        // Recreate reports...
        Collections.reverse(deletedReports);
        for (String reportInternalName : deletedReports) {
            TableInfo table = this.findTableContainingReportWithoutChecks(reportInternalName, request);
            HibernateUtil.activateObject(table);
            BaseReportInfo reportToRecreate = table.getReport(reportInternalName);
            String CreateViewSQL = "CREATE VIEW " + reportInternalName + " AS ("
                    + reportToRecreate.getSQLForDetail() + ")";
            statement = conn.prepareStatement(CreateViewSQL);
            statement.execute();
            statement.close();
        }
    } catch (SQLException sqlex) {
        conn.rollback(savepoint);
        throw new SQLException("The requested change would cause an error in the report: " + sqlex.getMessage()
                + ". SQL = " + statement, sqlex.getSQLState(), sqlex);
    }
}

From source file:org.apache.hadoop.hive.metastore.txn.TxnHandler.java

/**
 * Concurrency/isolation notes://from  w  ww . j  ava2 s. c  o m
 * This is mutexed with {@link #openTxns(OpenTxnRequest)} and other {@link #commitTxn(CommitTxnRequest)}
 * operations using select4update on NEXT_TXN_ID.  Also, mutexes on TXNX table for specific txnid:X
 * see more notes below.
 * In order to prevent lost updates, we need to determine if any 2 transactions overlap.  Each txn
 * is viewed as an interval [M,N]. M is the txnid and N is taken from the same NEXT_TXN_ID sequence
 * so that we can compare commit time of txn T with start time of txn S.  This sequence can be thought of
 * as a logical time counter.  If S.commitTime < T.startTime, T and S do NOT overlap.
 *
 * Motivating example:
 * Suppose we have multi-statment transactions T and S both of which are attempting x = x + 1
 * In order to prevent lost update problem, the the non-overlapping txns must lock in the snapshot
 * that they read appropriately.  In particular, if txns do not overlap, then one follows the other
 * (assumig they write the same entity), and thus the 2nd must see changes of the 1st.  We ensure
 * this by locking in snapshot after 
 * {@link #openTxns(OpenTxnRequest)} call is made (see {@link org.apache.hadoop.hive.ql.Driver#acquireLocksAndOpenTxn()})
 * and mutexing openTxn() with commit().  In other words, once a S.commit() starts we must ensure
 * that txn T which will be considered a later txn, locks in a snapshot that includes the result
 * of S's commit (assuming no other txns).
 * As a counter example, suppose we have S[3,3] and T[4,4] (commitId=txnid means no other transactions
 * were running in parallel).  If T and S both locked in the same snapshot (for example commit of
 * txnid:2, which is possible if commitTxn() and openTxnx() is not mutexed)
 * 'x' would be updated to the same value by both, i.e. lost update. 
 */
@Override
@RetrySemantics.Idempotent("No-op if already committed")
public void commitTxn(CommitTxnRequest rqst) throws NoSuchTxnException, TxnAbortedException, MetaException {
    long txnid = rqst.getTxnid();
    try {
        Connection dbConn = null;
        Statement stmt = null;
        ResultSet lockHandle = null;
        ResultSet commitIdRs = null, rs;
        try {
            lockInternal();
            dbConn = getDbConn(Connection.TRANSACTION_READ_COMMITTED);
            stmt = dbConn.createStatement();
            /**
             * Runs at READ_COMMITTED with S4U on TXNS row for "txnid".  S4U ensures that no other
             * operation can change this txn (such acquiring locks). While lock() and commitTxn()
             * should not normally run concurrently (for same txn) but could due to bugs in the client
             * which could then corrupt internal transaction manager state.  Also competes with abortTxn().
             */
            lockHandle = lockTransactionRecord(stmt, txnid, TXN_OPEN);
            if (lockHandle == null) {
                //if here, txn was not found (in expected state)
                TxnStatus actualTxnStatus = findTxnState(txnid, stmt);
                if (actualTxnStatus == TxnStatus.COMMITTED) {
                    /**
                     * This makes the operation idempotent
                     * (assume that this is most likely due to retry logic)
                     */
                    LOG.info("Nth commitTxn(" + JavaUtils.txnIdToString(txnid) + ") msg");
                    return;
                }
                raiseTxnUnexpectedState(actualTxnStatus, txnid);
                shouldNeverHappen(txnid);
                //dbConn is rolled back in finally{}
            }
            String conflictSQLSuffix = "from TXN_COMPONENTS where tc_txnid=" + txnid
                    + " and tc_operation_type IN(" + quoteChar(OpertaionType.UPDATE.sqlConst) + ","
                    + quoteChar(OpertaionType.DELETE.sqlConst) + ")";
            rs = stmt.executeQuery(sqlGenerator.addLimitClause(1, "tc_operation_type " + conflictSQLSuffix));
            if (rs.next()) {
                close(rs);
                //if here it means currently committing txn performed update/delete and we should check WW conflict
                /**
                 * This S4U will mutex with other commitTxn() and openTxns(). 
                 * -1 below makes txn intervals look like [3,3] [4,4] if all txns are serial
                 * Note: it's possible to have several txns have the same commit id.  Suppose 3 txns start
                 * at the same time and no new txns start until all 3 commit.
                 * We could've incremented the sequence for commitId is well but it doesn't add anything functionally.
                 */
                commitIdRs = stmt
                        .executeQuery(sqlGenerator.addForUpdateClause("select ntxn_next - 1 from NEXT_TXN_ID"));
                if (!commitIdRs.next()) {
                    throw new IllegalStateException("No rows found in NEXT_TXN_ID");
                }
                long commitId = commitIdRs.getLong(1);
                Savepoint undoWriteSetForCurrentTxn = dbConn.setSavepoint();
                /**
                 * "select distinct" is used below because
                 * 1. once we get to multi-statement txns, we only care to record that something was updated once
                 * 2. if {@link #addDynamicPartitions(AddDynamicPartitions)} is retried by caller it my create
                 *  duplicate entries in TXN_COMPONENTS
                 * but we want to add a PK on WRITE_SET which won't have unique rows w/o this distinct
                 * even if it includes all of it's columns
                 */
                int numCompsWritten = stmt.executeUpdate(
                        "insert into WRITE_SET (ws_database, ws_table, ws_partition, ws_txnid, ws_commit_id, ws_operation_type)"
                                + " select distinct tc_database, tc_table, tc_partition, tc_txnid, " + commitId
                                + ", tc_operation_type " + conflictSQLSuffix);
                /**
                 * see if there are any overlapping txns wrote the same element, i.e. have a conflict
                 * Since entire commit operation is mutexed wrt other start/commit ops,
                 * committed.ws_commit_id <= current.ws_commit_id for all txns
                 * thus if committed.ws_commit_id < current.ws_txnid, transactions do NOT overlap
                 * For example, [17,20] is committed, [6,80] is being committed right now - these overlap
                 * [17,20] committed and [21,21] committing now - these do not overlap.
                 * [17,18] committed and [18,19] committing now - these overlap  (here 18 started while 17 was still running)
                 */
                rs = stmt.executeQuery(sqlGenerator.addLimitClause(1,
                        "committed.ws_txnid, committed.ws_commit_id, committed.ws_database,"
                                + "committed.ws_table, committed.ws_partition, cur.ws_commit_id cur_ws_commit_id, "
                                + "cur.ws_operation_type cur_op, committed.ws_operation_type committed_op "
                                + "from WRITE_SET committed INNER JOIN WRITE_SET cur "
                                + "ON committed.ws_database=cur.ws_database and committed.ws_table=cur.ws_table "
                                +
                                //For partitioned table we always track writes at partition level (never at table)
                                //and for non partitioned - always at table level, thus the same table should never
                                //have entries with partition key and w/o
                                "and (committed.ws_partition=cur.ws_partition or (committed.ws_partition is null and cur.ws_partition is null)) "
                                + "where cur.ws_txnid <= committed.ws_commit_id" + //txns overlap; could replace ws_txnid
                                // with txnid, though any decent DB should infer this
                                " and cur.ws_txnid=" + txnid + //make sure RHS of join only has rows we just inserted as
                                // part of this commitTxn() op
                                " and committed.ws_txnid <> " + txnid + //and LHS only has committed txns
                                //U+U and U+D is a conflict but D+D is not and we don't currently track I in WRITE_SET at all
                                " and (committed.ws_operation_type=" + quoteChar(OpertaionType.UPDATE.sqlConst)
                                + " OR cur.ws_operation_type=" + quoteChar(OpertaionType.UPDATE.sqlConst)
                                + ")"));
                if (rs.next()) {
                    //found a conflict
                    String committedTxn = "[" + JavaUtils.txnIdToString(rs.getLong(1)) + "," + rs.getLong(2)
                            + "]";
                    StringBuilder resource = new StringBuilder(rs.getString(3)).append("/")
                            .append(rs.getString(4));
                    String partitionName = rs.getString(5);
                    if (partitionName != null) {
                        resource.append('/').append(partitionName);
                    }
                    String msg = "Aborting [" + JavaUtils.txnIdToString(txnid) + "," + rs.getLong(6) + "]"
                            + " due to a write conflict on " + resource + " committed by " + committedTxn + " "
                            + rs.getString(7) + "/" + rs.getString(8);
                    close(rs);
                    //remove WRITE_SET info for current txn since it's about to abort
                    dbConn.rollback(undoWriteSetForCurrentTxn);
                    LOG.info(msg);
                    //todo: should make abortTxns() write something into TXNS.TXN_META_INFO about this
                    if (abortTxns(dbConn, Collections.singletonList(txnid), true) != 1) {
                        throw new IllegalStateException(msg + " FAILED!");
                    }
                    dbConn.commit();
                    close(null, stmt, dbConn);
                    throw new TxnAbortedException(msg);
                } else {
                    //no conflicting operations, proceed with the rest of commit sequence
                }
            } else {
                /**
                 * current txn didn't update/delete anything (may have inserted), so just proceed with commit
                 *
                 * We only care about commit id for write txns, so for RO (when supported) txns we don't
                 * have to mutex on NEXT_TXN_ID.
                 * Consider: if RO txn is after a W txn, then RO's openTxns() will be mutexed with W's
                 * commitTxn() because both do S4U on NEXT_TXN_ID and thus RO will see result of W txn.
                 * If RO < W, then there is no reads-from relationship.
                 */
            }
            // Move the record from txn_components into completed_txn_components so that the compactor
            // knows where to look to compact.
            String s = "insert into COMPLETED_TXN_COMPONENTS select tc_txnid, tc_database, tc_table, "
                    + "tc_partition from TXN_COMPONENTS where tc_txnid = " + txnid;
            LOG.debug("Going to execute insert <" + s + ">");
            int modCount = 0;
            if ((modCount = stmt.executeUpdate(s)) < 1) {
                //this can be reasonable for an empty txn START/COMMIT or read-only txn
                //also an IUD with DP that didn't match any rows.
                LOG.info("Expected to move at least one record from txn_components to "
                        + "completed_txn_components when committing txn! " + JavaUtils.txnIdToString(txnid));
            }
            s = "delete from TXN_COMPONENTS where tc_txnid = " + txnid;
            LOG.debug("Going to execute update <" + s + ">");
            modCount = stmt.executeUpdate(s);
            s = "delete from HIVE_LOCKS where hl_txnid = " + txnid;
            LOG.debug("Going to execute update <" + s + ">");
            modCount = stmt.executeUpdate(s);
            s = "delete from TXNS where txn_id = " + txnid;
            LOG.debug("Going to execute update <" + s + ">");
            modCount = stmt.executeUpdate(s);
            LOG.debug("Going to commit");
            dbConn.commit();
        } catch (SQLException e) {
            LOG.debug("Going to rollback");
            rollbackDBConn(dbConn);
            checkRetryable(dbConn, e, "commitTxn(" + rqst + ")");
            throw new MetaException(
                    "Unable to update transaction database " + StringUtils.stringifyException(e));
        } finally {
            close(commitIdRs);
            close(lockHandle, stmt, dbConn);
            unlockInternal();
        }
    } catch (RetryException e) {
        commitTxn(rqst);
    }
}