Skip to content

Commit

Permalink
Test App: Add Java code for transaction retries
Browse files Browse the repository at this point in the history
Add example code for transaction retry logic. Compilation and
execution instructions are in a comment in the main code file.
Fixes cockroachdb#757.
  • Loading branch information
rjnn authored and Arjun Narayan committed Jan 11, 2017
1 parent 09bfdfd commit fa6cc52
Showing 1 changed file with 88 additions and 0 deletions.
88 changes: 88 additions & 0 deletions _includes/app/txn-sample.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import java.sql.*;

/*
TODO(jseldess): This file needs to be renamed to TxnSample.java to
fit with Java naming conventions (see BasicSample.java). I've held
off on that as that needs renamings on the rest of the doc page.
You can compile and run this example with a command like:
javac TxnSample.java && java -cp .:~/path/to/postgresql-9.4.1208.jar TxnSample
You can download the postgres JDBC driver jar from https://jdbc.postgresql.org.
*/

class InsufficientBalanceException extends Exception {}

// A simple interface that provides a retryable lambda expression.
interface RetryableTransaction {
public void run(Connection conn) throws Exception;
}

public class TxnSample {
public static RetryableTransaction transferFunds(int from, int to, int amount) {
return new RetryableTransaction() {
public void run(Connection conn) throws Exception {
ResultSet res = conn.createStatement().executeQuery("SELECT balance FROM accounts WHERE id = " + from);
res.next();
int balance = res.getInt("balance");
if(balance < from) {
throw new InsufficientBalanceException();
}
conn.createStatement().executeUpdate("UPDATE accounts SET balance = balance - " + amount + " where id = " + from);
conn.createStatement().executeUpdate("UPDATE accounts SET balance = balance + " + amount + " where id = " + to);
}
};
}

public static void retryTransaction(Connection conn, RetryableTransaction tx) throws Exception {
Savepoint sp = conn.setSavepoint("cockroach_restart");
while(true) {
try {
// Attempt the transaction.
tx.run(conn);

// If we reach this point, commit the transaction,
// which implicitly releases the savepoint.
conn.commit();
break;
} catch(SQLException e) {
// Check if the error code indicates a SERIALIZATION_FAILURE.
if(e.getErrorCode() == 40001) {
// Signal the database that we will attempt a retry.
conn.rollback(sp);
}
// This is a not a serialization failure, pass it up the chain.
throw e;
}
}
}

public static void main(String[] args) throws ClassNotFoundException, SQLException {
// Load the postgres JDBC driver.
Class.forName("org.postgresql.Driver");

// Connect to the "bank" database.
Connection db = DriverManager.getConnection("jdbc:postgresql://127.0.0.1:26257/bank?sslmode=disable", "maxroach", "");
try {
// We need to turn off autocommit mode to allow for
// multi-statement transactions.
db.setAutoCommit(false);

RetryableTransaction transfer = transferFunds(1, 2, 100);
retryTransaction(db, transfer);
ResultSet res = db.createStatement().executeQuery("SELECT id, balance FROM accounts");
while (res.next()) {
System.out.printf("\taccount %s: %s\n", res.getInt("id"), res.getInt("balance"));
}
} catch(InsufficientBalanceException ibe) {
System.out.println("Insufficient balance");
} catch(SQLException sqle) {
System.out.println("SQLException encountered:" + sqle);
} catch(Exception e) {
System.out.println("Unknown exception encountered:" + e);
} finally {
// Close the database connection.
db.close();
}
}
}

0 comments on commit fa6cc52

Please sign in to comment.