PreparedStatementCallback作为一个接口,其中只有一个函数doInPrepatedStatement,这个函数是用于调用通用方法execute的时候无法处理的一些个性化处理方法,在update中的函数实现:
protected int update(final PreparedStatementCreator psc, final PreparedStatementSetter pss) throws DataAccessException { logger.debug("Executing prepared SQL update"); return execute(psc, new PreparedStatementCallback<Integer>() { public Integer 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 rows; } finally { if (pss instanceof ParameterDisposer) { ((ParameterDisposer) pss).cleanupParameters(); } } } }); }
其中真正执行SQL的ps.executeUpdate并没有太多需要讲的,但是,对于设置输入参数的函数pss.setValues(ps),可以分析一下。
在没有分析源码之前,我们至少可以知道其功能,回顾下Spring中使用SQL的执行过程,直接使用:
jdbcTemplate.update("insert into user(name,age,sex)values(?,?,?)",
new Object[] { user.getName(), user.getAge(),user.getSex() },
new int[] { java.sql.Types.VARCHAR,java.sql.Types.INTEGER, java.sql.Types.VARCHAR });
SQL语句对应的参数,对应参数的类型清晰明了,这都归功于Spring为我们做了封装,而真正的JDBC调用其实非常繁琐,你需要这么做:
PreparedStatement updateSales = con.prepareStatement("insert into user(name,age, sex)values(?,?,?)");
updateSales.setString(1, user.getName());
updateSales.setInt(2, user.getAge());
updateSales.setString(3, user.getSex());
那么看看Spring是如何做到封装上面的操作呢?首先,所有的操作都是以pss.setValues(ps)为入口的。这个pss所代表的正式ArgumentTypePreparedStatementSetter。其中的setValues如下:
public void setValues(PreparedStatement ps) throws SQLException { int parameterPosition = 1; if (this.args != null) { //遍历每个参数以作类型匹配及转换 for (int i = 0; i < this.args.length; i++) { Object arg = this.args[i]; //如果是集合类则需要进入集合类内部递归解析集合内部属性 if (arg instanceof Collection && this.argTypes[i] != Types.ARRAY) { Collection entries = (Collection) arg; for (Object entry : entries) { if (entry instanceof Object[]) { Object[] valueArray = ((Object[]) entry); for (Object argValue : valueArray) { doSetValue(ps, parameterPosition, this.argTypes[i], argValue); parameterPosition++; } } else { doSetValue(ps, parameterPosition, this.argTypes[i], entry); parameterPosition++; } } } else { //解析当前属性 doSetValue(ps, parameterPosition, this.argTypes[i], arg); parameterPosition++; } } } }
对单个参数及类型的匹配处理:
private static void setParameterValueInternal(PreparedStatement ps, int paramIndex, int sqlType, String typeName, Integer scale, Object inValue) throws SQLException { String typeNameToUse = typeName; int sqlTypeToUse = sqlType; Object inValueToUse = inValue; // override type info? if (inValue instanceof SqlParameterValue) { SqlParameterValue parameterValue = (SqlParameterValue) inValue; if (logger.isDebugEnabled()) { logger.debug("Overriding type info with runtime info from SqlParameterValue: column index " + paramIndex + ", SQL type " + parameterValue.getSqlType() + ", type name " + parameterValue.getTypeName()); } if (parameterValue.getSqlType() != SqlTypeValue.TYPE_UNKNOWN) { sqlTypeToUse = parameterValue.getSqlType(); } if (parameterValue.getTypeName() != null) { typeNameToUse = parameterValue.getTypeName(); } inValueToUse = parameterValue.getValue(); } if (logger.isTraceEnabled()) { logger.trace("Setting SQL statement parameter value: column index " + paramIndex + ", parameter value [" + inValueToUse + "], value class [" + (inValueToUse != null ? inValueToUse.getClass().getName() : "null") + "], SQL type " + (sqlTypeToUse == SqlTypeValue.TYPE_UNKNOWN ? "unknown" : Integer.toString(sqlTypeToUse))); } if (inValueToUse == null) { setNull(ps, paramIndex, sqlTypeToUse, typeNameToUse); } else { setValue(ps, paramIndex, sqlTypeToUse, typeNameToUse, scale, inValueToUse); } }