- 前言
- 第一部分 核心实现
- 第 1 章 Spring 整体架构和环境搭建
- 第 2 章 容器的基本实现
- 第 3 章 默认标签的解析
- 第 4 章 自定义标签的解析
- 第 5 章 bean 的加载
- 第 6 章 容器的功能扩展
- 第 7 章 AOP
- 第二部分 企业应用
- 第 8 章 数据库连接 JDBC
- 第 9 章 整合 MyBatis
- 第 10 章 事务
- 第 11 章 SpringMVC
- 第 12 章 远程服务
- 第 13 章 Spring 消息
8.2.2 Update 中的回调函数
PreparedStatementCallback 作为一个接口,其中只有一个函数 doInPreparedStatement,这个函数是用于调用通用方法 execute 的时候无法处理的一些个性化处理方法,在 update 中的函数实现:
public Integer doInPreparedStatement(PreparedStatement ps) throws SQLException {
try {
if (pss != null) {
//设置 PreparedStatement 所需的全部参数。
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 没有太多需要讲解的,因为我们平时在直接使用 JDBC 方式进行调用的时候会经常使用此方法。但是,对于设置输入参数的函数 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 所代表的当前类正是 ArgPreparedStatementSetter。其中的 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 (Iterator it = entries.iterator(); it.hasNext();) {
Object entry = it.next();
if (entry instanceof Object[]) {
Object[] valueArray = ((Object[])entry);
for (int k = 0; k < valueArray.length; k++) {
Object argValue = valueArray[k];
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++;
}
}
}
}
对单个参数及类型的匹配处理:
protected void doSetValue(PreparedStatement ps, int parameterPosition, int argType, Object argValue)
throws SQLException {
StatementCreatorUtils.setParameterValue(ps, parameterPosition, argType, argValue);
}
public static void setParameterValue(
PreparedStatement ps, int paramIndex, int sqlType, Object inValue)
throws SQLException {
setParameterValueInternal(ps, paramIndex, sqlType, null, null, inValue);
}
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;
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);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论