Ich bin im Frühjahr auf ein gutes Beispiel gestoßen. Das Framework verwendet das Konzept lokaler Klassendefinitionen innerhalb der Methode, um verschiedene Datenbankoperationen auf einheitliche Weise zu behandeln.
Angenommen, Sie haben einen Code wie diesen:
JdbcTemplate jdbcOperations = new JdbcTemplate(this.myDataSource);
jdbcOperations.execute("call my_stored_procedure()")
jdbcOperations.query(queryToRun, new MyCustomRowMapper(), withInputParams);
jdbcOperations.update(queryToRun, withInputParams);
Schauen wir uns zunächst die Implementierung von execute () an:
@Override
public void execute(final String sql) throws DataAccessException {
if (logger.isDebugEnabled()) {
logger.debug("Executing SQL statement [" + sql + "]");
}
/**
* Callback to execute the statement.
(can access method local state like sql input parameter)
*/
class ExecuteStatementCallback implements StatementCallback<Object>, SqlProvider {
@Override
@Nullable
public Object doInStatement(Statement stmt) throws SQLException {
stmt.execute(sql);
return null;
}
@Override
public String getSql() {
return sql;
}
}
//transforms method input into a functional Object
execute(new ExecuteStatementCallback());
}
Bitte beachten Sie die letzte Zeile. Spring macht genau diesen "Trick" auch für den Rest der Methoden:
//uses local class QueryStatementCallback implements StatementCallback<T>, SqlProvider
jdbcOperations.query(...)
//uses local class UpdateStatementCallback implements StatementCallback<Integer>, SqlProvider
jdbcOperations.update(...)
Der "Trick" mit lokalen Klassen ermöglicht es dem Framework, alle diese Szenarien in einer einzigen Methode zu behandeln, die diese Klassen über die StatementCallback-Schnittstelle akzeptiert. Diese einzelne Methode fungiert als Brücke zwischen Aktionen (Ausführen, Aktualisieren) und allgemeinen Vorgängen (z. B. Ausführung, Verbindungsverwaltung, Fehlerübersetzung und Ausgabe der DBMS-Konsole).
public <T> T execute(StatementCallback<T> action) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
Connection con = DataSourceUtils.getConnection(obtainDataSource());
Statement stmt = null;
try {
stmt = con.createStatement();
applyStatementSettings(stmt);
//
T result = action.doInStatement(stmt);
handleWarnings(stmt);
return result;
}
catch (SQLException ex) {
// Release Connection early, to avoid potential connection pool deadlock
// in the case when the exception translator hasn't been initialized yet.
String sql = getSql(action);
JdbcUtils.closeStatement(stmt);
stmt = null;
DataSourceUtils.releaseConnection(con, getDataSource());
con = null;
throw translateException("StatementCallback", sql, ex);
}
finally {
JdbcUtils.closeStatement(stmt);
DataSourceUtils.releaseConnection(con, getDataSource());
}
}