views:

119

answers:

2

I have three methods that, together, save a node to the database. Currently, this does not achieve the desired effect of not committing the changes unless all the writes are successful.

    conn.setAutoCommit(false);
    writeNodeTable(node, newNodeNID);
    writeContentTypeBoutTable(node, newNodeNID);
    writeTerms(node, newNodeNID);
    conn.commit();

If there is a problem (such as an uncaught exception is thrown) in the second or third method, I'd like to roll back all the changes. Is there some way I can use transactions to do this?

This is one such DB writing function:

private void writeTerms(DrupalNode node, int newNodeNID) throws SQLException {
    String sql = "INSERT INTO term_node (nid, vid, tid) VALUES (?, ?, ?)";
    PreparedStatement prep = conn.prepareStatement(sql);
    prep.setInt(1, newNodeNID);
    prep.setInt(2, newNodeNID);

    String schoolName = termHelp.schoolOfAgainst(node.get(BoutField.against));
    prep.setString(3, schoolName);

    prep.execute();

    String fencerName = termHelp.fencerOfAgainst(node.get(BoutField.against));
    prep.setString(3, fencerName);
    prep.execute();
    prep.close();
}
+1  A: 

You can use rollback method in Connection interface. http://java.sun.com/j2se/1.5.0/docs/api/java/sql/Connection.html#rollback()

Also you have to set setAutoCommit to false and call commit and rollback methods as appropriately.

Upul
+1. Maybe you need to stress the need to "commit" more. Otherwise nothing will be saved in the DB, even if there is no "rollback".
Thilo
Wouldn't work, unless you use same connection object. No negative cast, however. The answer still provides a little insight.
Adeel Ansari
@Vinegar: Yes, one would need to use the same connection object (and also not commit in any of the three methods themselves).
Thilo
+2  A: 

Upul is correct, you would need to implement the Connection.setAutoCommit(false) and the Connection.rollback() methods. One thing you might want to try for each transaction is to have this sort of flow:

Connection conn = null; // or have the connection sent in
try {
    conn = getConnection(username, password);
    conn.setAutoCommit(false);
    // do stuff with connection
    conn.commit();
} catch (SQLException sqle) {
    // handle error appropriately
    conn.rollback();
} finally {
    // cleanup
    conn.close(); // depends on when the connection was allocated
}
bogertron
If the first got commit, you will no more be able to rollback when exception occur in the second or third.
Adeel Ansari
@Vinegar the idea is to not do any commits until everything has been processed. I probably should have added that all three calls should have been executed in the do stuff with connection piece
bogertron
You still says, "One thing you might want to try for **each transaction** is to have this sort of flow". Which is not gonna work.
Adeel Ansari
@Vinegar, Maybe this is how I think of a transaction, but I imagine a transaction beginning when one allocates a database connection and a transaction ending when the connection object is committed or rolled back. So I'm imagining that all the changes [writeTable, writeContentTypeBoutTable, writeTerms] are happening between when the connection is first 'created' (depends on connection pooling strategy) and when the connection gets committed or rolled back.
bogertron
And all 3 of those method should not have this sort of flow. Am I right? Those will just use the connection object to prepare the statement. Edited your post to revoke the negative, since **meanings** are much more important than **words**.
Adeel Ansari
@Vinegar, Correct, this flow should executed from the caller of the three methods, which is similar to what you have suggested in your post.
bogertron