ฉันเจอตัวอย่างที่ดีในฤดูใบไม้ผลิ เฟรมเวิร์กใช้แนวคิดของนิยามคลาสโลคัลภายในเมธอดเพื่อจัดการกับการดำเนินการฐานข้อมูลต่างๆในลักษณะเดียวกัน
สมมติว่าคุณมีรหัสดังนี้:
JdbcTemplate jdbcOperations = new JdbcTemplate(this.myDataSource);
jdbcOperations.execute("call my_stored_procedure()")
jdbcOperations.query(queryToRun, new MyCustomRowMapper(), withInputParams);
jdbcOperations.update(queryToRun, withInputParams);
ก่อนอื่นเรามาดูการใช้งาน execute ():
@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());
}
โปรดสังเกตบรรทัดสุดท้าย Spring ทำ "เคล็ดลับ" ที่แน่นอนสำหรับวิธีการอื่น ๆ เช่นกัน:
//uses local class QueryStatementCallback implements StatementCallback<T>, SqlProvider
jdbcOperations.query(...)
//uses local class UpdateStatementCallback implements StatementCallback<Integer>, SqlProvider
jdbcOperations.update(...)
"เคล็ดลับ" กับคลาสโลคัลช่วยให้เฟรมเวิร์กจัดการกับสถานการณ์เหล่านั้นทั้งหมดในวิธีการเดียวซึ่งยอมรับคลาสเหล่านั้นผ่านอินเทอร์เฟซ StatementCallback วิธีการเดียวนี้ทำหน้าที่เป็นสะพานเชื่อมระหว่างการดำเนินการ (ดำเนินการอัปเดต) และการดำเนินการทั่วไปรอบ ๆ ตัว (เช่นการดำเนินการการจัดการการเชื่อมต่อการแปลข้อผิดพลาดและเอาต์พุตคอนโซล 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());
}
}