Tôi đã xem qua một ví dụ điển hình vào mùa xuân. Khung đang sử dụng khái niệm định nghĩa lớp cục bộ bên trong phương thức để xử lý các hoạt động cơ sở dữ liệu khác nhau một cách thống nhất.
Giả sử bạn có một đoạn mã như sau:
JdbcTemplate jdbcOperations = new JdbcTemplate(this.myDataSource);
jdbcOperations.execute("call my_stored_procedure()")
jdbcOperations.query(queryToRun, new MyCustomRowMapper(), withInputParams);
jdbcOperations.update(queryToRun, withInputParams);
Đầu tiên chúng ta hãy xem xét việc triển khai thực thi ():
@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());
}
Hãy lưu ý dòng cuối cùng. Spring cũng thực hiện "mẹo" chính xác này đối với các phương pháp còn lại:
//uses local class QueryStatementCallback implements StatementCallback<T>, SqlProvider
jdbcOperations.query(...)
//uses local class UpdateStatementCallback implements StatementCallback<Integer>, SqlProvider
jdbcOperations.update(...)
"Thủ thuật" với các lớp cục bộ cho phép khuôn khổ xử lý tất cả các tình huống đó trong một phương thức duy nhất chấp nhận các lớp đó thông qua giao diện StatementCallback. Phương thức đơn này hoạt động như một cầu nối giữa các hành động (thực thi, cập nhật) và các hoạt động phổ biến xung quanh chúng (ví dụ: thực thi, quản lý kết nối, dịch lỗi và đầu ra bảng điều khiển dbms)
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());
}
}