Modified the code to initiate the connection before the first action and

to ensure that we are connected before every database operation. This
allows our connection to transiently fail even after the first operation,
but then be properly established once the database is again available.


git-svn-id: https://samskivert.googlecode.com/svn/trunk@116 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
mdb
2001-05-26 03:22:25 +00:00
parent 1b26f235c1
commit 98b01bd225
2 changed files with 42 additions and 16 deletions
@@ -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; package com.samskivert.jdbc;
@@ -29,6 +29,9 @@ public abstract class MySQLRepository extends Repository
protected int lastInsertedId () protected int lastInsertedId ()
throws SQLException throws SQLException
{ {
// make sure we've got a connection
ensureConnection();
// we have to do this by hand. alas all is not roses. // we have to do this by hand. alas all is not roses.
Statement stmt = _session.connection.createStatement(); Statement stmt = _session.connection.createStatement();
ResultSet rs = stmt.executeQuery("select LAST_INSERT_ID()"); ResultSet rs = stmt.executeQuery("select LAST_INSERT_ID()");
@@ -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; package com.samskivert.jdbc;
@@ -22,8 +22,8 @@ import com.samskivert.jdbc.jora.*;
public abstract class Repository public abstract class Repository
{ {
/** /**
* Creates the repository and opens music database. A properties * Creates and initializes the repository. A properties object should
* object should be supplied with the following fields: * be supplied with the following fields:
* *
* <pre> * <pre>
* driver=[jdbc driver class] * driver=[jdbc driver class]
@@ -32,6 +32,15 @@ public abstract class Repository
* password=[jdbc password] * password=[jdbc password]
* </pre> * </pre>
* *
* <p> The connection to the database will not be established until
* the first operation is executed. It is important that database
* operations be invoked via <code>execute()</code> 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 <code>ensureConnection()</code> before performing any
* database activity.
*
* @param props a properties object containing the configuration * @param props a properties object containing the configuration
* parameters for the repository. * parameters for the repository.
*/ */
@@ -48,19 +57,29 @@ public abstract class Repository
_password = _password =
requireProp(props, "password", "No driver password specified."); requireProp(props, "password", "No driver password specified.");
// establish a connection to the database // we attempt to reestablish the connection if there's a transient
establishConnection(); // 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. */ /** Establishes a connection to the database. */
protected void establishConnection () protected void ensureConnection ()
throws SQLException throws SQLException
{ {
// bail out if we've already got a connection // nothing doing if we've already got a connection
if (_session != null) { if (_session != null) {
return; 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 { try {
// create our JORA session // create our JORA session
_session = new Session(_dclass); _session = new Session(_dclass);
@@ -105,15 +124,15 @@ public abstract class Repository
// first close the old connection // first close the old connection
shutdown(); shutdown();
// then open a new one // then open a new one
establishConnection(); ensureConnection();
} }
/** /**
* After the database session is begun, this function will be called * After the database session is begun, this function will be called
* to give the repository implementation the opportunity to create its * to give the repository implementation the opportunity to create its
* table objects. As this is done during the initialization of the * table objects. If the database session fails, a new session will be
* repository, the implementation has a chance to fail the entire * established and this function will be called again for the new
* repository creation process if the necessary tables do not exist. * session.
*/ */
protected abstract void createTables () throws SQLException; protected abstract void createTables () throws SQLException;
@@ -153,8 +172,9 @@ public abstract class Repository
} }
/** /**
* Executes the supplied operation without attempting to reestablish * Executes the supplied operation. In the event of a transient
* the database connection in the event of a transient failure. * failure, the repository will attempt to reestablish the database
* connection and try the operation again.
*/ */
protected void execute (Operation op) protected void execute (Operation op)
throws SQLException throws SQLException
@@ -168,7 +188,7 @@ public abstract class Repository
* which case a call to rollback() is executed on the session. * which case a call to rollback() is executed on the session.
* *
* @param retryOnTransientFailure if true and the operation fails due * @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 * or deadlock detection), the connection to the database will be
* reestablished and the operation attempted once more. * reestablished and the operation attempted once more.
*/ */
@@ -176,7 +196,7 @@ public abstract class Repository
throws SQLException throws SQLException
{ {
// make sure our connection is established // make sure our connection is established
establishConnection(); ensureConnection();
try { try {
// invoke the operation // invoke the operation
@@ -260,4 +280,7 @@ public abstract class Repository
protected String _url; protected String _url;
protected String _username; protected String _username;
protected String _password; protected String _password;
// we use this to prevent too many database connection attempts
protected Throttle _throttle;
} }