学习《廖雪峰java课程》,看到Spring开发-访问数据库-使用JDBC这一章节时,对比源码
public User getUserByName(String name) {
return jdbcTemplate.execute("SELECT * FROM users WHERE name = ?", (PreparedStatement ps) -> {
ps.setObject(1, name);
try (var rs = ps.executeQuery()) {
if (rs.next()) {
return new User( // new User object:
rs.getLong("id"), // id
rs.getString("email"), // email
rs.getString("password"), // password
rs.getString("name")); // name
}
throw new RuntimeException("user not found by id.");
}
});
}
这个方法首先有个lambda表达式,没有看懂,又返回到函数式编程-lambda基础这一章节学习,
在Java程序中,我们经常遇到一大堆单方法接口,即一个接口只定义了一个方法
例如有这么一个方法:
@parm Rice 大米
@parm doFood 做法,这是一个接口,具体实例可以自定义,包括:炒米饭、蒸米饭等
public void getFood(Rice r , DoFood df){
df.do(r);
}
// 下面是一个只定义一个方法的接口
public interface DoFood{
void do(Rice r);
}
如果要使用getFood,通常的办法是定义一个实现DoFood接口的类
public Class FriedFood implement DoFood{
@Override
public void do(Rice r){
System.out.println("炒米饭”);
}
}
具体调用
getFood(new Rice(),new FiredFood());
如果用lambda表达式,可以简写成
getFood(new Rice(),(Rice r)->{System.out.println("炒米饭”);});
只需要写出方法定义即可,接着看代码:
查看源码,上面 jdbcTemplate.execute()的实现如下
public <T> T execute(String sql, PreparedStatementCallback<T> action) throws DataAccessException {
return this.execute((PreparedStatementCreator)(new SimplePreparedStatementCreator(sql)), (PreparedStatementCallback)action);
}
可以看到,第二个参数是 PreparedStatementCallback,接着查看这个定义
@FunctionalInterface
public interface PreparedStatementCallback<T> {
@Nullable
T doInPreparedStatement(PreparedStatement var1) throws SQLException, DataAccessException;
}
很明显,这是一个@FunctionalInterface的接口,可以用lambda表达式简写,注意:这个接口用泛型定义了一个方法,<T>是声明T这个泛型而已。
继续跟踪this.execute,这个方法
public <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action) throws DataAccessException {
Assert.notNull(psc, "PreparedStatementCreator must not be null");
Assert.notNull(action, "Callback object must not be null");
if (this.logger.isDebugEnabled()) {
String sql = getSql(psc);
this.logger.debug("Executing prepared SQL statement" + (sql != null ? " [" + sql + "]" : ""));
}
Connection con = DataSourceUtils.getConnection(this.obtainDataSource());
PreparedStatement ps = null;
Object var13;
try {
ps = psc.createPreparedStatement(con); // 语句 1
this.applyStatementSettings(ps);
T result = action.doInPreparedStatement(ps); // 语句 2
this.handleWarnings((Statement)ps);
var13 = result;
} catch (SQLException var10) {
if (psc instanceof ParameterDisposer) {
((ParameterDisposer)psc).cleanupParameters();
}
String sql = getSql(psc);
psc = null;
JdbcUtils.closeStatement(ps);
ps = null;
DataSourceUtils.releaseConnection(con, this.getDataSource());
con = null;
throw this.translateException("PreparedStatementCallback", sql, var10);
} finally {
if (psc instanceof ParameterDisposer) {
((ParameterDisposer)psc).cleanupParameters();
}
JdbcUtils.closeStatement(ps);
DataSourceUtils.releaseConnection(con, this.getDataSource());
}
return var13;
}
语句1 就是通过sql 创建 conn,并通过conn得到preparedstatement,有了这个preparedstatement,就可以把它传给doInPreparedStatement(),具体实现方法是
{
ps.setObject(1, name);
try (var rs = ps.executeQuery()) {
if (rs.next()) {
return new User( // new User object:
rs.getLong("id"), // id
rs.getString("email"), // email
rs.getString("password"), // password
rs.getString("name")); // name
}
}
可以看到就是设置“name”,然后填充User并返回,因为这个方法返回的是User,也就是T 就是 User,excute返回的就是User,正好与getUser的返回值相符。
== 函数式编程,可以理解传入的是一个函数,也可以理解就是一个接口的匿名继承 ==
可以查看 public T execute(ConnectionCallback action) 这个方法,更容易理解,实际上就是传入了一个接口而已,我们自己去实现这个接口唯一的方法doInConnection(Connection var1),通过方法名称可以很形象的理解,我们在这个方法里就是操作Connection就行,excute方法会传入一个实例的conn到doInConnection里