日期:2014-05-16  浏览次数:20603 次

spring中jdbcTemplate归纳2


用语句创建器更新数据库
第一个回调接口是PerparedStatementCreator,实现这个接口来覆盖整个更新过程的语句创建任务。我们先看下源代码中的PerparedStatementCreator接口,然后实现我们自己的接

口。

?

public interface PreparedStatementCreator {

	/** 
	 * Create a statement in this connection. Allows implementations to use
	 * PreparedStatements. The JdbcTemplate will close the created statement.
	 * @param con Connection to use to create statement
	 * @return a prepared statement
	 * @throws SQLException there is no need to catch SQLExceptions
	 * that may be thrown in the implementation of this method.
	 * The JdbcTemplate class will handle them.
	 */
	PreparedStatement createPreparedStatement(Connection con) throws SQLException;

}

?

源代码中只定义了一个方法createPreparedStatement,在connection连接的基础上创建statement,使我们可以使用PreparedStatements实例,创建完,jdbcTemplate会自动关闭

Connection连接,下面我们实现这个接口。

public class InsertPreparedStatementCreator implements PreparedStatementCreator{
	
	private User user;

	public InsertPreparedStatementCreator(User user){
		this.user = user;
	}

	public PreparedStatement createPreparedStatement(Connection conn)throws Exception{
		String sql = "insert into user value(?,?);
		PreparedStatement ps  = conn.prepareStatement(sql);
		ps.setString(user.getUsername());
		ps.setString(user.getPassword());
		return ps;
	}
}

?

我们实现后,只需要创建PreparedStatement ,并且把参数绑定上去,然后返回,在处理过程中不需要进行异常处理,因为方法签名中已经给我们抛出了异常,也不用关闭数据库

连接或者打开数据库连接,这些spring都给我们做好了,然后调用jdbcTemplate中的update方法即可。
jdbcTemplate.update(new InsertPreparedStatementCreator(user));
当然也可以用另一种方式。

?

jdbcTemplate.update(new PreparedStatementCreator(){
		String sql = "insert into user value(?,?);
		PreparedStatement ps  = conn.prepareStatement(sql);
		ps.setString(user.getUsername());
		ps.setString(user.getPassword());
		return ps;
});

?

这里其实是个回调函数,在设计模式中是模板方法模式。
模板方法使用继承机制实现。在父类中定义不变的,然后把变化的定义成一个抽象方法,供子类实现。因此模板方法的 父类一般也是一个抽象类。
在jdbcTemplate中的执行:
我们的update方法调用了jdbcTemplate方法中的

?

public int update(PreparedStatementCreator psc) throws DataAccessException {
		return update(psc, (PreparedStatementSetter) null);
}

?

接着调用

protected int update(final PreparedStatementCreator psc, final PreparedStatementSetter pss)
			throws DataAccessException {

		if (logger.isDebugEnabled()) {
			String sql = getSql(psc);
			logger.debug("Executing SQL update" + (sql != null ? " [" + sql  + "]" : ""));
		}
		Integer result = (Integer) execute(psc, new PreparedStatementCallback() {
			public Object doInPreparedStatement(PreparedStatement ps) throws SQLException {
				try {
					if (pss != null) {
						pss.setValues(ps);
					}
					int rows = ps.executeUpdate();
					if (logger.isDebugEnabled()) {
						logger.debug("SQL update affected " + rows + " rows");
					}
					return new Integer(rows);
				}
				finally {
					if (pss instanceof ParameterDisposer) {
						((ParameterDisposer) pss).cleanupParameters();
					}
				}
			}
		});
		return result.intValue();
	}

?

?

方法的关键:
int rows = ps.executeUpdate();
return new Integer(rows);
执行了preparedStatement.executeUpdate().然后返回执行后的值,和我们自己写是一样。在这里还是没有看到spring是如何打开数据库连接的。继续看,注意到一个方法的调用

Integer result = (Integer) execute(psc, new PreparedStatementCallback() 。。。。。。
我们找到这个方法

?

public Object execute(PreparedStatementCreator psc, PreparedStatementCallback action)
			throws DataAccessException {

		Assert.notNull(psc, "PreparedStatementCreator must not be null");
		Assert.notNull(action, "Callback object must not be null");

		Connection con = DataSourceUtils.getConnection(getDataSource());
		PreparedStatement ps = null;
		try {
			Connection conToUse = con;
			if (this.nativeJdbcExtractor != null &&
					this.nativeJdbcExtractor.isNati