這段在說如何使用JdbcTemplate,原始的JDBC會需要很多細節的撰寫,例如connection的取得,以及處理SqlException等等的boilerplate code,而這些可以透過JdbcTemplate來省略。
raw JDBC:
@Override
public Optional<Ingredient> findById(String id) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = dataSource.getConnection();
statement = connection.prepareStatement(
"select id, name, type from Ingredient where id=?");
statement.setString(1, id);
resultSet = statement.executeQuery();
Ingredient ingredient = null;
if(resultSet.next()) {
ingredient = new Ingredient(
resultSet.getString("id"),
resultSet.getString("name"),
Ingredient.Type.valueOf(resultSet.getString("type")));
}
return Optional.of(ingredient);
} catch (SQLException e) {
/* do some log */
} finally {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {}
}
}
return Optional.empty();
}
JdbcTemplate:
private JdbcTemplate jdbcTemplate;
public Optional<Ingredient> findById(String id) {
List<Ingredient> results = jdbcTemplate.query(
"select id, name, type from Ingredient where id=?",
this::mapRowToIngredient,
id);
return results.size() == 0 ?
Optional.empty() :
Optional.of(results.get(0));
}
private Ingredient mapRowToIngredient(ResultSet row, int rowNum)
throws SQLException {
return new Ingredient(
row.getString("id"),
row.getString("name"),
Ingredient.Type.valueOf(row.getString("type")));
}
不過當遇到了物件與物件之間aggregate的現象時,就還是很麻煩了,比如訂單的id是由db自動產生,但訂單中的產品又需要on上訂單的id,而產品本身的成分資訊也需要on上產品的db自動產生id,所以當我們要新增一筆訂單時,實際上背後需動員不只訂單一個物件。
以上情況若只用JdbcTemplate寫,也得每個相扣的環節都手動來寫。