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

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: PreparedStatementCallback作为一个接口,其中只有一个函数doInPrepatedStatement,这个函数是用于调用通用方法execute的时候无法处理的一些个性化处理方法,在update中的函数实现:protected int update(final Prepare...

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

 

 

目录
相关文章
|
Java 关系型数据库 MySQL
SpringJDBC解析1-使用示例
JDBC(Java Data Base Connectivity,Java数据库连接)是一种用于执行SQL语句的JavaAPI,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。
1013 0
|
SQL Java 数据库连接
SpringJDBC解析2-execute方法
大家都使用过JDBCTEMPLATE的execute方法,execute作为数据库操作的核心入口,将大多数数据库操作相同的步骤统一封装,而将个性化的操作使用参数PreparedStatementCallback回调。
1077 0
|
SQL
SpringJDBC解析4-query方法
重要步骤说明: 首先是从PersonServiceImpl方法进去,调用JdbcTemplate的query方法,然后执行一连串错中复杂的调用,而且里面有很多函数都是以回调形式处理, 1)JdbcTemplate接受到query请求,由于query没有带参数,所以选择不带sql参数的重载方法query执行。
1109 0
|
1月前
|
算法 测试技术 C语言
深入理解HTTP/2:nghttp2库源码解析及客户端实现示例
通过解析nghttp2库的源码和实现一个简单的HTTP/2客户端示例,本文详细介绍了HTTP/2的关键特性和nghttp2的核心实现。了解这些内容可以帮助开发者更好地理解HTTP/2协议,提高Web应用的性能和用户体验。对于实际开发中的应用,可以根据需要进一步优化和扩展代码,以满足具体需求。
135 29
|
5月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
160 2
|
1月前
|
前端开发 数据安全/隐私保护 CDN
二次元聚合短视频解析去水印系统源码
二次元聚合短视频解析去水印系统源码
53 3
|
1月前
|
JavaScript 算法 前端开发
JS数组操作方法全景图,全网最全构建完整知识网络!js数组操作方法全集(实现筛选转换、随机排序洗牌算法、复杂数据处理统计等情景详解,附大量源码和易错点解析)
这些方法提供了对数组的全面操作,包括搜索、遍历、转换和聚合等。通过分为原地操作方法、非原地操作方法和其他方法便于您理解和记忆,并熟悉他们各自的使用方法与使用范围。详细的案例与进阶使用,方便您理解数组操作的底层原理。链式调用的几个案例,让您玩转数组操作。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
1月前
|
移动开发 前端开发 JavaScript
从入门到精通:H5游戏源码开发技术全解析与未来趋势洞察
H5游戏凭借其跨平台、易传播和开发成本低的优势,近年来发展迅猛。接下来,让我们深入了解 H5 游戏源码开发的技术教程以及未来的发展趋势。
|
1月前
|
负载均衡 JavaScript 前端开发
分片上传技术全解析:原理、优势与应用(含简单实现源码)
分片上传通过将大文件分割成多个小的片段或块,然后并行或顺序地上传这些片段,从而提高上传效率和可靠性,特别适用于大文件的上传场景,尤其是在网络环境不佳时,分片上传能有效提高上传体验。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
1月前
|
存储 前端开发 JavaScript
在线教育网课系统源码开发指南:功能设计与技术实现深度解析
在线教育网课系统是近年来发展迅猛的教育形式的核心载体,具备用户管理、课程管理、教学互动、学习评估等功能。本文从功能和技术两方面解析其源码开发,涵盖前端(HTML5、CSS3、JavaScript等)、后端(Java、Python等)、流媒体及云计算技术,并强调安全性、稳定性和用户体验的重要性。

热门文章

最新文章

推荐镜像

更多