深入解析spring架构与设计原理-数据库的操作实现

     2022-03-18     666

关键词:

关于Spring JDBC
还是从Spring JDBC说起吧,虽然现在应用很多都是直接使用Hibernate或者其他的ORM工具。但JDBC毕竟还是很基本的,其中的JdbcTemplate就是我们经常使用的,比如JDBCTemplate的execute方法,就是一个基本的方法,在这个方法的实现中,可以看到对数据库操作的基本过程。


//execute方法执行的是输入的sql语句  
public void execute(final String sql) throws DataAccessException {  
    if (logger.isDebugEnabled()) {  
        logger.debug("Executing SQL statement [" + sql + "]");  
    }  
    class ExecuteStatementCallback implements StatementCallback<Object>, SqlProvider {  
        public Object doInStatement(Statement stmt) throws SQLException {  
            stmt.execute(sql);  
            return null;  
        }  
        public String getSql() {  
            return sql;  
        }  
    }  
    execute(new ExecuteStatementCallback());  
}  
//这是使用java.sql.Statement处理静态SQL语句的方法  
public <T> T execute(StatementCallback<T> action) throws DataAccessException {  
    Assert.notNull(action, "Callback object must not be null");  
    //这里取得数据库的Connection,这个数据库的Connection已经在Spring的事务管理之下  
    Connection con = DataSourceUtils.getConnection(getDataSource());  
    Statement stmt = null;  
    try {  
        Connection conToUse = con;  
        if (this.nativeJdbcExtractor != null &&  
                this.nativeJdbcExtractor.isNativeConnectionNecessaryForNativeStatements()) {  
            conToUse = this.nativeJdbcExtractor.getNativeConnection(con);  
        }  
        //创建Statement  
        stmt = conToUse.createStatement();  
        applyStatementSettings(stmt);  
        Statement stmtToUse = stmt;  
        if (this.nativeJdbcExtractor != null) {  
            stmtToUse = this.nativeJdbcExtractor.getNativeStatement(stmt);  
        }  
        //这里调用回调函数  
        T result = action.doInStatement(stmtToUse);  
        handleWarnings(stmt);  
        return result;  
    }  
    catch (SQLException ex) {  
        // Release Connection early, to avoid potential connection pool deadlock  
        // in the case when the exception translator hasn‘t been initialized yet.  
        //如果捕捉到数据库异常,把数据库Connection释放,同时抛出一个经过Spring转换过的Spring数据库异常  
        //Spring做了一项有意义的工作,就是把这些数据库异常统一到自己的异常体系里了  
        JdbcUtils.closeStatement(stmt);  
        stmt = null;  
        DataSourceUtils.releaseConnection(con, getDataSource());  
        con = null;  
        throw getExceptionTranslator().translate("StatementCallback", getSql(action), ex);  
    }  
    finally {  
        JdbcUtils.closeStatement(stmt);  
        //释放数据库connection  
        DataSourceUtils.releaseConnection(con, getDataSource());  
    }  
}  


在使用数据库的时候,有一个很重要的地方就是对数据库连接的管理,在这里,是由DataSourceUtils来完成的。Spring通过这个辅助类来对数据的Connection进行管理。比如通过它来完成打开和关闭Connection等操作。DataSourceUtils对这些数据库Connection管理的实现, 如以下代码所示。


//这是取得数据库连接的调用,实现是通过调用doGetConnection完成的,这里执行了异常的转换操作  
public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {  
    try {  
        return doGetConnection(dataSource);  
    }  
    catch (SQLException ex) {  
        throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex);  
    }  
}  
public static Connection doGetConnection(DataSource dataSource) throws SQLException {  
    Assert.notNull(dataSource, "No DataSource specified");  
    //把对数据库的Connection放到事务管理中进行管理,这里使用TransactionSynchronizationManager中定义的ThreadLocal变量来和线程绑定数据库连接  
    //如果在TransactionSynchronizationManager中已经有与当前线程绑定数据库连接,那就直接取出来使用  
    ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);  
    if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {  
        conHolder.requested();  
        if (!conHolder.hasConnection()) {  
            logger.debug("Fetching resumed JDBC Connection from DataSource");  
            conHolder.setConnection(dataSource.getConnection());  
        }  
        return conHolder.getConnection();  
    }  
    // Else we either got no holder or an empty thread-bound holder here.  
    // 这里得到需要的数据库Connection,在Bean配置文件中定义好的,  
    // 同时最后把新打开的数据库Connection通过TransactionSynchronizationManager和当前线程绑定起来。  
    logger.debug("Fetching JDBC Connection from DataSource");  
    Connection con = dataSource.getConnection();  
  
    if (TransactionSynchronizationManager.isSynchronizationActive()) {  
        logger.debug("Registering transaction synchronization for JDBC Connection");  
        // Use same Connection for further JDBC actions within the transaction.  
        // Thread-bound object will get removed by synchronization at transaction completion.  
        ConnectionHolder holderToUse = conHolder;  
        if (holderToUse == null) {  
            holderToUse = new ConnectionHolder(con);  
        }  
        else {  
            holderToUse.setConnection(con);  
        }  
        holderToUse.requested();  
        TransactionSynchronizationManager.registerSynchronization(  
                new ConnectionSynchronization(holderToUse, dataSource));  
        holderToUse.setSynchronizedWithTransaction(true);  
        if (holderToUse != conHolder) {  
            TransactionSynchronizationManager.bindResource(dataSource, holderToUse);  
        }  
    }  
    return con;  
}  


关于数据库操作类RDBMS
从JdbcTemplate中,我们看到,他提供了许多简单查询和更新的功能。但是,如果需要更高层次的抽象,以及更面向对象的方法来访问数据库,Spring为我们提供了org.springframework.jdbc.object包,里面包含了SqlQuery、SqlMappingQuery、SqlUpdate和StoredProcedure等类,这些类都是Spring JDBC应用程序可以使用的。但要注意,在使用这些类时需要为它们配置好JdbcTemplate作为其基本的操作实现,因为在它们的功能实现中,对数据库操作的那部分实现基本上还是依赖于JdbcTemplate来完成的。

比如,对MappingSqlQuery使用的过程,是非常简洁的;在设计好数据的映射代码之后,查询得到的记录已经按照前面的设计转换为对象List了,一条查询记录对应于一个数据对象,可以把数据库的数据记录直接映射成Java对象在程序中使用,同时又可避免使用第三方ORM工具的配置,对于简单的数据映射场合是非常方便的;在mapRow方法的实现中提供的数据转换规则,和我们使用Hibernate时,Hibernate的hbm文件起到的作用是非常类似的。这个MappingSqlQuery需要的对设置进行compile,这些compile是这样完成的,如以下代码所示:


protected final void compileInternal() {  
    //这里是对参数的compile过程,所有的参数都在getDeclaredParameters里面,生成了一个PreparedStatementCreatorFactory  
    this.preparedStatementFactory = new PreparedStatementCreatorFactory(getSql(), getDeclaredParameters());  
    this.preparedStatementFactory.setResultSetType(getResultSetType());  
    this.preparedStatementFactory.setUpdatableResults(isUpdatableResults());  
    this.preparedStatementFactory.setReturnGeneratedKeys(isReturnGeneratedKeys());  
    if (getGeneratedKeysColumnNames() != null) {  
        this.preparedStatementFactory.setGeneratedKeysColumnNames(getGeneratedKeysColumnNames());  
    }  
his.preparedStatementFactory.setNativeJdbcExtractor(getJdbcTemplate().getNativeJdbcExtractor());  
    onCompileInternal();  


在执行查询时,执行的实际上是SqlQuery的executeByNamedParam方法,这个方法需要完成的工作包括配置SQL语句,配置数据记录到数据对象的转换的RowMapper,然后使用JdbcTemplate来完成数据的查询,并启动数据记录到Java数据对象的转换,如以下代码所示:


public List<T> executeByNamedParam(Map<String, ?> paramMap, Map context) throws DataAccessException {  
    validateNamedParameters(paramMap);  
    //得到需要执行的SQL语句  
    ParsedSql parsedSql = getParsedSql();  
    MapSqlParameterSource paramSource = new MapSqlParameterSource(paramMap);  
    String sqlToUse = NamedParameterUtils.substituteNamedParameters(parsedSql, paramSource);  
    //配置好SQL语句需要的Parameters及rowMapper,这个rowMapper完成数据记录到对象的转换  
    Object[] params = NamedParameterUtils.buildValueArray(parsedSql, paramSource, getDeclaredParameters());  
    RowMapper<T> rowMapper = newRowMapper(params, context);  
    //我们又看到了JdbcTemplate,这里使用JdbcTemplate来完成对数据库的查询操作,所以我们说JdbcTemplate是非常基本的操作类  
        return getJdbcTemplate().query(newPreparedStatementCreator(sqlToUse, params), rowMapper);  
}  


在Spring对JDBC的操作中,基本上是对JDBC/Hibernate基础上API的封装。这些封装可以直接使用,也可以在IoC容器中配置好了再使用,当结合IoC容器的基础上进行使用的时候,可以看到许多和事务管理相关的处理部分,都是非常值得学习的,在那里,可以看到对数据源的管理 - Hibernate中session的管理,与线程的结合等等。

更多内容请关注微信公众号:IT哈哈(it_haha)

技术分享


本文出自 “doujh” 博客,请务必保留此出处http://doujh.blog.51cto.com/10177066/1933904

ios之深入解析渲染的底层原理

一、计算机渲染原理①CPU与GPU的架构对于现代计算机系统,简单来说可以大概视作三层架构:硬件、操作系统与进程。对于移动端来说,进程就是App,而CPU与GPU是硬件层面的重要组成部分。CPU与GPU提供了计算能力,通过操作系统... 查看详情

2017java必读书籍

1、深入理解Java虚拟机:JVM高级特性与最佳实践2、Oracle查询优化改写技巧与案例3、EffectiveJava4、Spring3.x企业应用开发实战5、Spring技术内幕:深入解析Spring架构与设计原理6、Java并发编程的艺术7、Java并发编程实战8、型网站系统与... 查看详情

2018年计划要看的书

  1、深入理解Java虚拟机:JVM高级特性与最佳实践2、java多线程核心技术3、EffectiveJava4, 待补充5、Spring技术内幕:深入解析Spring架构与设计原理6、Java并发编程的艺术7、Java并发编程实战8、型网站系统与Java中间件实践9... 查看详情

《深入理解tensorflow架构设计与实现原理》_彭靖田学习材料整理

 本书从基本概念、内部实现和实践等方面深剖析了TensorFlow。书中首先介绍了TensorFlow设计目标、基本架构、环境准备和基础概念,着重介绍了以数据流图为核心的机器学习编程框架的设计原则与核心实现,紧着还将TensorFlow与... 查看详情

操作系统架构原理-资源管理技术与进程的抽象设计

...学和互联网技术,掌握扎实的计算机基础知识,深入理解数据结构、算法和操作系统知识。操作系统定义定义: 操作系统(OperatingSystem,OS)尚无严格的定义。例如: 1.OS是管理系统资源、控制程序执行、改善... 查看详情

操作系统架构原理资源管理技术与进程的抽象设计思想

...学和互联网技术,掌握扎实的计算机基础知识,深入理解数据结构、算法和操作系统知识。操作系统定义定义: 操作系统(OperatingSystem,OS)尚无严格的定义。例如: 1.OS是管理系统资源、控制程序执... 查看详情

阅读书单2020

JAVA并发编程实战BrianGoetz深入理解kafka:核心设计与实践原理Maven实战Grale实战Spring实战(第四版)Spring源码深度解析(第2版)从Paxos到ZooKeeper分布式一致性原理实战MySQL技术内幕InnoDB存储引擎第2版MyBatis从入门到精通MongoDB实战(第... 查看详情

ios之深入解析app的架构设计

一、概述①应用架构App架构是软件设计的一个分支,它关心的是如何设计一个App的结构。具体来说,它关注于两个方面:如何将App分解为不同的接口和概念层次部件,以及这些部件之间和自身的不同操作中所使用... 查看详情

有啥好书讲解spring框架的原理和用法的麽

...方法注入,例如把DAO等注入到一个业务逻辑的类中来实现数据库操作,从而使类与类之间的联系更小,耦合度就小。AOP一般用于事务管理。spring功能很强大,如果不用的话可能实现以上功能很复杂的。spring框架有什么用?spring框... 查看详情

spring学习笔记

Spring学习笔记(一)因为最近在看《Spring技术内幕-深入解析Spring架构与设计原理》,相当于做了个笔记,以及把自己理解的东西记录下来。Spring整体架构图1.Spring子项目1.1SpringFramework(Core)  Spring项目的核心,其中包含IOC容器,... 查看详情

深入学习hbase架构原理

概述  Hbase与HDFS对比  Hbase表的特点  行存储与列存储 Hbase逻辑视图  Hbase数据模型 Hbase支持的操作 Hbase物理存储      Hbase基本架构   &nbs 查看详情

深入yarn系列1:窥全貌之yarn架构,设计,通信原理等(代码片段)

 深入YARN系列主要分为:深入YARN系列1:窥全貌之YARN架构,设计,通信原理等深入YARN系列2:剖析ResourceManager的架构与组件使用深入YARN系列3:剖析NodeManager架构,组件与生产应用深入YARN系列4:剖析... 查看详情

深入分析javaweb技术内幕

一、深入web请求过程1.1B/S网络架构概述1.2如何发起一个请求1.3HTTP解析1.3.1浏览器缓存机制CTRL+F51.4DNS域名解析1.4.1DNS域名解析过程1.5  CDN工作机制1.5.1CDN动态加速二、设计模式2.1 适配器模式2.2装饰模式2.3访问者模式2.4门面设计... 查看详情

架构设计深入学习02--概念架构与细化架构

胜兵先胜而后求战,败兵先战而后求胜—《孙子兵法》。这部分有些内容比较陈旧,但原理和思路还是一致的。 通常来说,概念架构满足"架构=组件+交互"且只关注高层组件,之后对齐进行笼统的界定,给为他们之间的关... 查看详情

旧调重弹hibernate与ibatis区别——深入架构设计

...学,hibernate相对较复杂,门槛较高。 但是,hibernate对数据库结构提供了较为完整的封装,hibernate的o/rmapping实现了pojo和数据库表之间的映射,以及sql的自动生成和执行。程序员往往只需定义好了pojo到数据库表的映射关系,即... 查看详情

深入解析spring中用到的九种设计模式

 设计模式作为工作学习中的枕边书,却时常处于勤说不用的尴尬境地,也不是我们时常忘记,只是一直没有记忆。今天,螃蟹在IT学习者网站就设计模式的内在价值做一番探讨,并以spring为例进行讲解,只有领略了其设计的... 查看详情

[笔记]深入解析windows操作系统《二》系统架构

文章目录​​前言​​​​2.1需求和设计目标​​​​2.2操作系统模型​​​​2.3系统架构​​​​系统软件层面组成​​​​2.4关键系统组件​​​​环境子系统和子系统DLL​​​​子系统启动​​​​Windows子系统​​​​... 查看详情

hadoop学习资料汇总

...书目百度网盘密码:gqfn《Hadoop权威指南(第二版中文)》《深入理解大数据(大数据处理与编程实践)》《Hadoop技术内幕深入解析HADOOPCOMMON和HDFS架构设计与实现原理》《Hadoop技术内幕深入理解MapReduce架构设计与实现原理》《Hadoop技术... 查看详情