学习《廖雪峰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"), // idrs.getString("email"), // emailrs.getString("password"), // passwordrs.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{@Overridepublic 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,接着查看这个定义
@FunctionalInterfacepublic interface PreparedStatementCallback<T> {@NullableT 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); // 语句 1this.applyStatementSettings(ps);T result = action.doInPreparedStatement(ps); // 语句 2this.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"), // idrs.getString("email"), // emailrs.getString("password"), // passwordrs.getString("name")); // name}}
可以看到就是设置“name”,然后填充User并返回,因为这个方法返回的是User,也就是T 就是 User,excute返回的就是User,正好与getUser的返回值相符。
== 函数式编程,可以理解传入的是一个函数,也可以理解就是一个接口的匿名继承 ==
可以查看 public T execute(ConnectionCallback action) 这个方法,更容易理解,实际上就是传入了一个接口而已,我们自己去实现这个接口唯一的方法doInConnection(Connection var1),通过方法名称可以很形象的理解,我们在这个方法里就是操作Connection就行,excute方法会传入一个实例的conn到doInConnection里