SpringJDBC解析3-回调函数(update为例)

Posted wade&luffy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringJDBC解析3-回调函数(update为例)相关的知识,希望对你有一定的参考价值。

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

 

 

以上是关于SpringJDBC解析3-回调函数(update为例)的主要内容,如果未能解决你的问题,请参考以下文章

SpringJDBC解析2-execute方法

mongoose V7.4核心篇之HTTP特定协议回调函数

如何正确继承Unity的回调函数,如Awake(),Start()和Update和FixedUpdate()?

SpringJDBC解析1-使用示例

44个 Javascript 变态题解析 (上下)

回调函数在命令解析中的应用