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); } }
?
?