`
rysh0818
  • 浏览: 23837 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

spring事务管理器设计思想(一)

 
阅读更多

在最近做的一个项目里面,涉及到多数据源的操作,比较特殊的是,这多个数据库的表结构完全相同,由于我们使用的ibatis框架作为持久化层,为了防止每一个数据源都配置一套规则,所以重新实现了数据源,根据线程变量中指定的数据库连接名称来获取实际的数据源。

一个简单的实现如下:

public class ProxyDataSource implements DataSource {
/** 数据源池配置 */
private Map<String, DataSource> dataSourcePoolConfig;

public Connection getConnection() throws SQLException {
        return createDataSource().getConnection();
}
private synchronized DataSource createDataSource() {
        String dbName = DataSourceContextHolder.getDbName();
        return dataSourcePoolConfig.get(dbName);
}

每次调用spring事务管理器之前,设置DataSourceContextHolder.set(“dbName”)

事务提交之后在调用 DataSourceContextHolder.clear() 方法即可

但是这样设计实际使用过程中也会遇到一些典型的问题,这就是在仔细了解spring中持久化层的设计之后,才能明白所产生的问题的原因。下面主要总结一下spring 持久化的设计。

Jdbc基本的编程模型

由于任何持久化层的封装实际上都是对java.sql.Connection等相关对象的操作,一个典型的数据操作的流程如下:

但在我们实际使用spring和ibatis的时候,都没有感觉到上面的流程,其实spring已经对外已经屏蔽了上述的操作,让我们更关注业务逻辑功能,但是我们有必要了解其实现,以便能够更好运用和定位问题。

开启事务:

在开启事务的时候,我们需要初始化事务上下文信息,以便在业务完成之后,需要知道事务的状态,以便进行后续的处理,这个上下文信息可以保存在 ThreadLocal里面,包括是否已经开启事务,事务的超时时间,隔离级别,传播级别,是否设置为回滚。这个信息对应用来说是透明的,但是提供给使用者编程接口,以便告知业务结束的时候是提交事务还是回滚事务。

获取连接

首先来看看spring如何获取数据库连接的,对于正常情况来看,获取连接直接调用DataSource.getConnection()就可以了,我们在自己实现的时候也肯定会这么做,但是需要考虑两种情况(这里面先不引入事务的传播属性):

1 还没有获取过连接,这是第一次获取连接

2 已经获取过连接,不是第一次获取连接,可以复用连接

解决获取数据库连接的关键问题就是如何判断是否已经可用的连接,而不需要开启新的数据库连接,同时由于数据库连接需要给后续的业务操作复用,如何保持这个连接,并且透明的传递给后续流程。对于一个简单的实现就是使用线程上下文变量ThrealLocal来解决以上两个问题。

具体的实现是:在获取数据库连接的时候,判断当前线程线程变量里面是否已经存在相关连接,如果不存在,就创新一个新的连接,如果存在,就直接获取其对应的连接。在第一次获取到数据库连接的时候,我们还需要做一些特殊处理,就是设置自动提交为false。在业务活动结束的时候在进行提交或者回滚。这个时候就是要调用connection.setAutoCommit(false)方法。

执行sql

这一部分和业务逻辑相关,通过对外提供一些编程接口,可以让业务决定业务完成之后如何处理事务,比较简单的就是设置事务状态。

提交事务:

在开启事务的时候,事务上下文信息已经保存在线程变量里面了,可以根据事务上下文的信息,来决定是否是提交还是回滚。其实就是调用数据库连接Connection.commit 和 Connection.rollback 方法。然后需要清空线程变量中的事务上下文信息。相当于结束了当前的事务。

关闭连接:

关闭连接相对比较简单,由于当前线程变量保存了连接信息,只需要获取连接之后,调用connection.close方法即可,接着清空线程变量的数据库连接信息。

上面几个流程是一个简单的事务处理流程,在spring中都有对应的实现,见TransactionTemplate.execute方法。Spring定义了一个TransactionSynchronizationManager对象,里面保存了各种线程变量信息,

//保存了数据源和其对应连接的映射,value是一个Map结构,其中key为datasource,value为其打开的连接

private static final ThreadLocal resources

//这个暂时用不到,不解释

private static final ThreadLocal synchronizations

//当前事务的名字

private static final ThreadLocal currentTransactionName

//是否是只读事务以及事务的隔离级别(这个一般我们都用不到,都是默认界别)

private static final ThreadLocal currentTransactionReadOnly

private static final ThreadLocal currentTransactionIsolationLevel

//代表是否是一个实际的事务活动,这个后面将)

private static final ThreadLocal actualTransactionActive

在获取连接的时候,可见DataSourceUtils.doGetConnection()方法,就是从调用TransactionSynchronizationManager.getResource(dataSource)获取连接信息,如果为空,就直接从调用dataSource.getConnection()创建新的连接,后面在调用

TransactionSynchronizationManager.bindResource(dataSource,conn)绑定数据源到线程变量,以便后续的线程在使用。

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

                   }

        

                   logger.debug("Fetching JDBC Connection from DataSource");

                   Connection con = dataSource.getConnection();

在提交事务的时候,见 DataSourceTransactionManager.doCommit方法,其实就是获取事务状态信息以及连接信息,调用conn.commmit方法,比较简单。

但是实际上,spring事务管理远远比上述复杂,我们没有考虑以下几种情况:

1 如果当前操作不需要事务支持,也就是每次执行一次,就自动进行提交。如何在同一个架构里面兼容这两种情况。比如就是简单的query操作。

2 一个业务活动跨越多个事务,每个事务的传播级别配置不一样。后面会拿一个例子来说明

对于第一个问题,比较好解决,首先就是根据线程变量里面获取数据源对应的连接,如果有连接,就复用。如果没有,就创建连接。在判断当前是否存在活动的事务上下文,如果存在事务信息,设置conn.setAutoCommit(false),然后设置线程上下文,绑定对应的数据源。如果不存在事务信息,就直接返回连接给应用。

这样就会带来一个新的问题,就是连接如何进行关闭。根据最开始的分析,在存在事务上下文的情况下,直接从获取线程获取对应的数据库连接,然后关闭。在关闭的也需要也进行判断一下即可。在spring里面,在事务中获取连接和关闭连接有一些特殊的处理,主要还是和其jdbc以及orm框架设计兼容。在jdbcTemplate,IbatiTemplate每执行一次sql操作,就需要获取conn,执行sql,关闭conn。如果不存在事务上下文,这样做没有任何问题,获取一次连接,使用完成,然后就是比。但是如果存在事务上下文,每次获取的conn并不一定是真实的物理连接,所以关闭的时候,也不能直接关闭这数据库连接。Spring的中定义一个ConnectionHandle对象,这个对象持有一个数据库连接对象,以及该连接上的引用次数(retain属性)。每次复用一次就retain++ 操作,没关闭一次,就执行retain-- 操作,在retain 为0的时候,说明没有任何连接,就可以进行真实的关闭了。

分享到:
评论

相关推荐

    Spring设计思想.ppt

    这样做的好处是降低了内存中对象的创建和销毁的开销,尤其是对于那些状态不随时间改变或者需要全局唯一性的对象,如数据源、事务管理器等,单态模式能显著提高系统性能。Spring通过控制bean的生命周期,自动管理其...

    Spring框架的事务管理应用分析.doc

    Spring框架是一个在2003年推出的开源项目,它的核心设计理念源于Rod Johnson的《Expert One-on-One J2EE Design and Development》一书中的实用主义J2EE思想。Spring框架主要包括一个容器、配置组件的框架和一系列...

    SpringBoot事务和Spring事务详讲

    这意味着开发者无需显式地定义这些事务管理器,Spring Boot 会根据应用中使用的持久化技术自动选择合适的事务管理器。 ##### 2. 注解驱动 Spring Boot 支持使用注解来控制事务的传播行为。例如,通过在方法上使用 `...

    aop与spring事务处理

    ### AOP与Spring事务处理详解 ...AOP 能够有效地将横切关注点从业务逻辑中分离出来,而Spring事务管理则为开发者提供了简单、灵活的方式来管理事务。这两种技术相结合,能够显著提高软件的质量和开发效率。

    Spring_框架的设计理念与设计模式分析

    Spring的核心设计思想之一是面向Bean的编程(BOP)。Bean是Spring框架中的核心概念,它封装了应用程序中的对象和服务。Spring通过管理这些Bean来实现对应用逻辑的支持,包括但不限于依赖注入、生命周期管理等功能。...

    Spring框架的设计理念与设计模式分析之一

    3. **AOP的支持**:Spring框架内置了对AOP的支持,可以方便地实现诸如日志记录、安全控制、事务管理等功能,而无需显式编写代码。 #### 四、核心组件如何协同工作 1. **Bean组件**:Bean组件负责定义Bean的结构、...

    Spring框架的设计理念与设计模式分析

    6. **策略模式**:Spring的事务管理策略,允许开发者选择不同的事务管理方式,如编程式事务管理、声明式事务管理等。 7. **适配器模式**:Spring通过适配器将不同来源的数据源(如JDBC、Hibernate、MyBatis等)统一...

    Spring技术内幕:深入解析Spring架构与设计原理(第2版)+.pdf

    Spring框架的主要目标是提供一种简单的方式来解决企业级应用程序开发中的常见问题,如依赖注入(Dependency Injection,DI)、面向切面编程(Aspect-Oriented Programming,AOP)以及事务管理等。 ### 核心容器与...

    Spring技术内幕:深入解析Spring架构与设计原理(第2版) .pdf

    4. **事务管理**:Spring提供了声明式事务管理功能,使得事务管理变得更加简单易用。 5. **MVC框架**:Spring的Web MVC框架是一种高度可配置的模型-视图-控制器框架,用于构建Web应用程序。 ### Spring架构分析 ...

    spring的核心思想

    它提供了全面的基础架构支持,包括但不限于依赖注入(Dependency Injection,简称DI)、面向切面编程(Aspect Oriented Programming,简称AOP)、数据访问/集成(Data Access/Integration)、事务管理(Transaction ...

    Spring技术内幕:深入解析Spring架构与设计原理

    总的来说,《Spring技术内幕:深入解析Spring架构与设计原理》是一本全面而深入的Spring指南,旨在帮助读者不仅掌握Spring的使用,更能理解其设计思想和实现原理,从而在实际开发中更加得心应手。通过阅读这本书,...

    spring核心思想

    Spring框架是Java开发中不可或缺的一部分,它以其丰富的功能和模块化设计深受开发者喜爱。Spring的核心思想主要体现在依赖注入(Dependency Injection, DI)和面向切面编程(Aspect-Oriented Programming, AOP)两个...

    SPRING技术内幕:深入解析SPRING架构与设计原理.pdf 下载

    Spring框架内置了对AOP的支持,允许开发者以声明式的方式实现横切关注点,如事务管理和日志记录等。这种机制能够将业务逻辑和系统服务分离,提高了代码的可维护性和可读性。 ### 四、Spring框架的优势 1. **非侵入...

    84丨开源实战四(上):剖析Spring框架中蕴含的经典设计思想或原则1

    例如,Spring的事务管理功能,通过声明式事务管理,开发者无需关心事务的开启、提交和回滚,只需在方法上添加注解即可。 通过以上设计思想的实践,Spring框架不仅提高了开发效率,还增强了系统的可扩展性和可维护性...

    (源码)基于SpringCloudNetflix的分布式事务管理系统.zip

    本项目是一个基于Spring Cloud Netflix框架的分布式事务管理系统,旨在解决微服务架构中的分布式事务一致性问题。项目采用TCC(TryConfirmCancel)设计思想,通过HTTP协议实现跨服务的分布式事务管理。系统通过...

    Spring技术内幕:深入解析Spring架构与设计原理(第2版)

    其次,AOP是Spring另一个核心概念,它允许将横切关注点(比如日志、事务管理等)从它们所影响的对象中分离出来,从而降低了代码的重复性和复杂度。Spring通过动态代理和字节码生成技术来实现AOP。 在第2版的书中,...

    第四章:Spring AOP API 设计模式1

    10. **代理模式(Proxy)**:Spring AOP的核心就是代理模式,它创建了目标对象的代理,代理对象在调用实际目标方法之前/之后执行额外的逻辑(如日志、事务管理等),提供了对对象行为的扩展。 11. **模板方法模式...

Global site tag (gtag.js) - Google Analytics