diff --git a/projects/samskivert/src/java/com/samskivert/jdbc/MySQLRepository.java b/projects/samskivert/src/java/com/samskivert/jdbc/MySQLRepository.java index 7e0222cd..0a7f8b5e 100644 --- a/projects/samskivert/src/java/com/samskivert/jdbc/MySQLRepository.java +++ b/projects/samskivert/src/java/com/samskivert/jdbc/MySQLRepository.java @@ -1,5 +1,5 @@ // -// $Id: MySQLRepository.java,v 1.3 2001/03/19 22:59:08 mdb Exp $ +// $Id: MySQLRepository.java,v 1.4 2001/05/26 03:22:24 mdb Exp $ package com.samskivert.jdbc; @@ -29,6 +29,9 @@ public abstract class MySQLRepository extends Repository protected int lastInsertedId () throws SQLException { + // make sure we've got a connection + ensureConnection(); + // we have to do this by hand. alas all is not roses. Statement stmt = _session.connection.createStatement(); ResultSet rs = stmt.executeQuery("select LAST_INSERT_ID()"); diff --git a/projects/samskivert/src/java/com/samskivert/jdbc/Repository.java b/projects/samskivert/src/java/com/samskivert/jdbc/Repository.java index 9fcd176c..533a7f6e 100644 --- a/projects/samskivert/src/java/com/samskivert/jdbc/Repository.java +++ b/projects/samskivert/src/java/com/samskivert/jdbc/Repository.java @@ -1,5 +1,5 @@ // -// $Id: Repository.java,v 1.4 2001/03/19 22:59:08 mdb Exp $ +// $Id: Repository.java,v 1.5 2001/05/26 03:22:25 mdb Exp $ package com.samskivert.jdbc; @@ -22,8 +22,8 @@ import com.samskivert.jdbc.jora.*; public abstract class Repository { /** - * Creates the repository and opens music database. A properties - * object should be supplied with the following fields: + * Creates and initializes the repository. A properties object should + * be supplied with the following fields: * *
* driver=[jdbc driver class]
@@ -32,6 +32,15 @@ public abstract class Repository
* password=[jdbc password]
*
*
+ * The connection to the database will not be established until
+ * the first operation is executed. It is important that database
+ * operations be invoked via execute() rather than
+ * directly so that the repository can manage the database session
+ * properly (reestablishing the session on transient failures and so
+ * on). If a derived class wishes to perform operations directly, it
+ * should call ensureConnection() before performing any
+ * database activity.
+ *
* @param props a properties object containing the configuration
* parameters for the repository.
*/
@@ -48,19 +57,29 @@ public abstract class Repository
_password =
requireProp(props, "password", "No driver password specified.");
- // establish a connection to the database
- establishConnection();
+ // we attempt to reestablish the connection if there's a transient
+ // failure (like the database is down or our old connection gets
+ // closed by the database), but we don't want to get too crazy
+ // about connecting to the database automatically, so we limit our
+ // attempts to twice every thirty seconds
+ _throttle = new Throttle(2, 30);
}
/** Establishes a connection to the database. */
- protected void establishConnection ()
+ protected void ensureConnection ()
throws SQLException
{
- // bail out if we've already got a connection
+ // nothing doing if we've already got a connection
if (_session != null) {
return;
}
+ // make sure we don't try to reestablish the connection
+ // overzealously in times of lengthy database outage
+ if (_throttle.throttleOp()) {
+ throw new SQLException("Connection attempt throttled.");
+ }
+
try {
// create our JORA session
_session = new Session(_dclass);
@@ -105,15 +124,15 @@ public abstract class Repository
// first close the old connection
shutdown();
// then open a new one
- establishConnection();
+ ensureConnection();
}
/**
* After the database session is begun, this function will be called
* to give the repository implementation the opportunity to create its
- * table objects. As this is done during the initialization of the
- * repository, the implementation has a chance to fail the entire
- * repository creation process if the necessary tables do not exist.
+ * table objects. If the database session fails, a new session will be
+ * established and this function will be called again for the new
+ * session.
*/
protected abstract void createTables () throws SQLException;
@@ -153,8 +172,9 @@ public abstract class Repository
}
/**
- * Executes the supplied operation without attempting to reestablish
- * the database connection in the event of a transient failure.
+ * Executes the supplied operation. In the event of a transient
+ * failure, the repository will attempt to reestablish the database
+ * connection and try the operation again.
*/
protected void execute (Operation op)
throws SQLException
@@ -168,7 +188,7 @@ public abstract class Repository
* which case a call to rollback() is executed on the session.
*
* @param retryOnTransientFailure if true and the operation fails due
- * to an transient failure (like losing the connection to the database
+ * to a transient failure (like losing the connection to the database
* or deadlock detection), the connection to the database will be
* reestablished and the operation attempted once more.
*/
@@ -176,7 +196,7 @@ public abstract class Repository
throws SQLException
{
// make sure our connection is established
- establishConnection();
+ ensureConnection();
try {
// invoke the operation
@@ -260,4 +280,7 @@ public abstract class Repository
protected String _url;
protected String _username;
protected String _password;
+
+ // we use this to prevent too many database connection attempts
+ protected Throttle _throttle;
}