spring transaction源码分析--事务架构

1. 引言 事务特性

事务是并发控制的单元,是用户定义的一个操做序列。这些操做要么都作,要么都不作,是一个不可分割的工做单位。经过事务将逻辑相关的一组操做绑定在一块儿,以便服务器 保持数据的完整性。事务一般是以begin transaction开始,以commit或rollback结束。Commint表示提交,即提交事务的全部操做。具体地说就是将事务中全部对数据的更新写回到磁盘上的物理数据库中去,事务正常结束。Rollback表示回滚,即在事务运行的过程当中发生了某种故障,事务不能继续进行,系统将事务中对数据库的全部已完成的操做所有撤消,滚回到事务开始的状态。html

  原子性(Atomic) 对数据的修改要么所有执行,要么所有不执行。java

  一致性(Consistent) 在事务执行先后,数据状态保持一致性。程序员

  隔离性(Isolated) 一个事务的处理不能影响另外一个事务的处理。spring

  持续性(Durable) 事务处理结束,其效果在数据库中持久化。sql

  1. Java事务的类型
    Java事务的类型有三种:JDBC事务、JTA(Java Transaction API)事务、容器事务。
    一、JDBC事务数据库

    JDBC 事务是用 Connection 对象控制的。JDBC Connection 接口( java.sql.Connection )提供了两种事务模式:自动提交和手工提交。 java.sql.Connection 提供了如下控制事务的方法:编程

  public void setAutoCommit(boolean)
  public boolean getAutoCommit()
  public void commit()
  public void rollback()bootstrap

使用 JDBC 事务界定时,您能够将多个 SQL 语句结合到一个事务中。JDBC 事务的一个缺点是事务的范围局限于一个数据库链接。一个 JDBC 事务不能跨越多个数据库。api

二、JTA(Java Transaction API)事务安全

JTA是一种高层的,与实现无关的,与协议无关的API,应用程序和应用服务器可使用JTA来访问事务。

JTA容许应用程序执行分布式事务处理——在两个或多个网络计算机资源上访问而且更新数据,这些数据能够分布在多个数据库上。JDBC驱动程序的JTA支持极大地加强了数据访问能力。

若是计划用 JTA 界定事务,那么就须要有一个实现 javax.sql.XADataSource 、 javax.sql.XAConnection 和 javax.sql.XAResource 接口的 JDBC 驱动程序。一个实现了这些接口的驱动程序将能够参与 JTA 事务。一个 XADataSource 对象就是一个 XAConnection 对象的工厂。 XAConnection s 是参与 JTA 事务的 JDBC 链接。

您将须要用应用服务器的管理工具设置 XADataSource .从应用服务器和 JDBC 驱动程序的文档中能够了解到相关的指导。

J2EE应用程序用 JNDI 查询数据源。一旦应用程序找到了数据源对象,它就调用 javax.sql.DataSource.getConnection() 以得到到数据库的链接。

XA 链接与非 XA 链接不一样。必定要记住 XA 链接参与了 JTA 事务。这意味着 XA 链接不支持 JDBC 的自动提交功能。同时,应用程序必定不要对 XA 链接调用 java.sql.Connection.commit() 或者 java.sql.Connection.rollback() .

相反,应用程序应该使用 UserTransaction.begin()、 UserTransaction.commit() 和 serTransaction.rollback() .

三、容器事务

容器事务主要是J2EE应用服务器提供的,容器事务大可能是基于JTA完成,这是一个基于JNDI的,至关复杂的API实现。相对编码实现JTA事务管理, 咱们能够经过EJB容器提供的容器事务管理机制(CMT)完成同一个功能,这项功能由J2EE应用服务器提供。这使得咱们能够简单的指定将哪一个方法加入事 务,一旦指定,容器将负责事务管理任务。这是咱们土建的解决方式,由于经过这种方式咱们能够将事务代码排除在逻辑编码以外,同时将全部困难交给J2EE容 器去解决。使用EJB CMT的另一个好处就是程序员无需关心JTA API的编码,不过,理论上咱们必须使用EJB.

四、三种Java事务差别

JDBC事务控制的局限性在一个数据库链接内,可是其使用简单。

JTA事务的功能强大,事务能够跨越多个数据库或多个DAO,使用也比较复杂。

 容器事务,主要指的是J2EE应用服务器提供的事务管理,局限于EJB应用使用。

五、应用场景

Java事务控制是构建J2EE应用不可缺乏的一部分,合理选择应用何种事务对整个应用系统来讲相当重要。通常说来,在单个JDBC 链接链接的状况下能够选择JDBC事务,在跨多个链接或者数据库状况下,须要选择使用JTA事务,若是用到了EJB,则能够考虑使用EJB容器事务

  1. spring事务实现源码分析

 3.1 dao模块
    dao模块定义了数据库层的各类异常,其中异常的结构已经在spring-jdbc模块中介绍过了,在这里主要是dao的支持和异常的转译,其数据库支持和转译结构以下所示:
spring transaction源码分析--事务架构
dao 支持
提供了对hibernate、jdbc,cci的支持。咱们都想到熟悉,对cci可能有些陌生,下面的章节会讲到。
dao异常转译
PersistenceExceptionTranslationPostProcessor:自动将标示为@repository的bean的持久化异常进行转译。它增长一个PersistenceExceptionTranslationAdvisor来代理相应的已经存在的aop代理或者实现了目标接口的新产生的代理。它将本地资源异常转换为spring的DataAccessException及其子类上。

PersistenceExceptionTranslationAdvisor是一个spring aop的异常转译类,它应用到respository层或者dao层。它基于给定的PersistenceExceptionTranslator来将本地持久化异常转换为spring的DataAccessException族。

 PersistenceExceptionTranslationInterceptor:一个aop 方法拦截器(MethodInterceptor).提供基于PersistenceExceptionTranslator的异常转换,它是PersistenceExceptionTranslator的代理,将运行时抛出的异常转换为spring 的DataAccessException族。

PersistenceExceptionTranslator spring集成其它数据获取技术(如jpa、toplink、jdo、hibernate等)抛出运行时异常的接口。

3.2 jca模块

  1. cci模块

    spring transaction源码分析--事务架构

J2EE提供JCA(Java Connector Architecture)规范来标准化对EIS(Enterprise Information System)的访问。这个规范被分为几个不一样的部分:

  SPI(Service provider interfaces)是链接器提供者(connector provider)必须实现的接口。 这些接口组成了一个能被部署在J2EE应用服务器上的资源适配器(resource adapter)。 在这种状况下,由服务器来管理链接池(connection pooling)、事务和安全(托管模式(managed mode))。 应用服务器还负责管理客户端应用程序以外所拥有的配置。链接器(connector)一样能在脱离应用服务器的状况下使用;在这种状况下,应用程序必须直接对它进行配置(非托管模式(non-managed mode))。

  CCI (Common Client Interface)是应用程序用来与链接器交互并与EIS通讯的接口。一样还为本地事务划界提供了API。

  Spring对CCI的支持,目的是为了提供以典型的Spring方式来访问CCI链接器的类,并有效地使用Spring的通用资源和事务管理工具。

注意:
链接器的客户端没必要老是使用CCI。 某些链接器暴露它们本身的API,只提供JCA资源适配器(resource adapter) 以使用J2EE容器的某些系统契约(system contracts)(链接池(connection pooling),全局事务(global transactions),安全(security))。 Spring并无为这类链接器特有(connector-specific)的API提供特殊的支持。

  1. context模块
    ResourceAdapterApplicationContext:一个jca ResourceAdapter的applicationContext实现,须要于jca的bootstrapContext一同初始化,最后传递到实现了BootstrapContextAware的spring 受管理bean。
    spring transaction源码分析--事务架构
@Override    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        beanFactory.addBeanPostProcessor(new BootstrapContextAwareProcessor(this.bootstrapContext));
        beanFactory.ignoreDependencyInterface(BootstrapContextAware.class);
        beanFactory.registerResolvableDependency(BootstrapContext.class, this.bootstrapContext);        // JCA WorkManager resolved lazily - may not be available.
        beanFactory.registerResolvableDependency(WorkManager.class, new ObjectFactory<WorkManager>() {
                @Override            public WorkManager getObject() {                return bootstrapContext.getWorkManager();
                }
        });
}

spring transaction源码分析--事务架构
BootstrapContextAwareProcessor:传递BootstrapContext到实现了BootStrapContextAware接口的spring bean。它在内部bean factory中自动注册。
BootstrapContextAware:须要通知BootStrapContext的实现类。
BootstrapContext:提供一种机制,这种机制将一个Bootstrap的上下文传递到一个资源适配器实例。
3.endpoint模块
AbstractMessageEndpointFactory:实现了jca 1.五、1.六、1.7版本的javax.resource.spi.endpoint.MessageEndpointFactory接口,它提供了事务管理能力。
GenericMessageEndpointFactory实现了抽象方法,对任意类型的消息监听对象(javax.jms.MessageListener)或者javax.resource.cci.MessageListener对象提供了事务管理的能力。
GenericMessageEndpointManager管理类,对上述方法进行管理。
4.support模块
LocalConnectionFactoryBean:建立一个本地JCA链接工厂。
ResourceAdapterFactoryBean :使用BootStrapContext启动一个jca 1.5指定的ResouceAdapter。

  1. work模块
    结构以下:
    spring transaction源码分析--事务架构
    WorkManager提供了提交Work(Work继承了Runnable)可执行实例的便利类。
    3.3 transaction模块

spring事务架构

3.3.1 事务管理PlatformTransactionManager的架构

以下图所示:

PlatformTransactionManager:spring事务的核心接口。

spring transaction源码分析--事务架构

3.3.2 事务定义TransactionDefinition的架构

以下图所示:
spring transaction源码分析--事务架构

TransactionDefinition:定义spring容器事务属性的接口。

包括事务传播行为类型和事务隔离级别:

事务传播行为类型

事务传播行为类型

说明

PROPAGATION_REQUIRED

若是当前没有事务,就新建一个事务,若是已经存在一个事务中,加入到这个事务中。这是最多见的选择。

PROPAGATION_SUPPORTS

支持当前事务,若是当前没有事务,就以非事务方式执行。

PROPAGATION_MANDATORY

使用当前的事务,若是当前没有事务,就抛出异常。

PROPAGATION_REQUIRES_NEW

新建事务,若是当前存在事务,把当前事务挂起。

PROPAGATION_NOT_SUPPORTED

以非事务方式执行操做,若是当前存在事务,就把当前事务挂起。

PROPAGATION_NEVER

以非事务方式执行,若是当前存在事务,则抛出异常。

PROPAGATION_NESTED

若是当前存在事务,则在嵌套事务内执行。若是当前没有事务,则执行与PROPAGATION_REQUIRED相似的操做。

当使用PROPAGATION_NESTED时,底层的数据源必须基于JDBC 3.0,而且实现者须要支持保存点事务机制。

隔离级别:

为了不上面出现几种状况在标准SQL规范中定义了4个事务隔离级别,不一样隔离级别对事务处理不一样

  1. 未受权读取(Read Uncommitted):也称未提交读。防止更新丢失(这不对应一级锁吗),若是一个事务已经开始写数据则另一个数据则不容许同时进行写操做但容许其余事务读此行数据。该隔离级别能够经过“排他写锁”实现。事务隔离的最低级别,仅可保证不读取物理损坏的数据。与READ COMMITTED 隔离级相反,它容许读取已经被其它用户修改但还没有提交肯定的数据。

  2. 受权读取(Read Committed):也称提交读。1之上防止脏读取(这不对应二级锁吗)。这能够经过“瞬间共享读锁”和“排他写锁”实现,读取数据的事务容许其余事务继续访问该行数据,可是未提交写事务将会禁止其余事务访问该行。SQL Server 默认的级别。在此隔离级下,SELECT 命令不会返回还没有提交(Committed) 的数据,也不能返回脏数据。

  3. 可重复读取(Repeatable Read):2之上防止不可重复读取(这不对应三级锁吗)。可是有时可能出现幻影数据,这能够经过“共享读锁”和“排他写锁”实现,读取数据事务将会禁止写事务(但容许读事务),写事务则禁止任何其余事务。在此隔离级下,用SELECT 命令读取的数据在整个命令执行过程当中不会被更改。此选项会影响系统的效能,非必要状况最好不用此隔离级。

  三级封锁协议并不能阻止幻读,修改的不能再被读取,可是新增(删除)的记录数能够统计。

  4. 串行(Serializable):也称可串行读(这不对应两段锁吗)。提供严格的事务隔离,它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行。若是仅仅经过 “行级锁”是没法实现事务序列化的,必须经过其余机制保证新插入的数据不会被刚执行查询操做事务访问到。事务隔离的最高级别,事务之间彻底隔离。若是事务在可串行读隔离级别上运行,则能够保证任何并发重叠事务均是串行的。

点击查看大图
spring transaction源码分析--事务架构
  LU丢失更新 DR脏读 NRR非重复读SLU二类丢失更新 PR幻像读

为了解决与“多个线程请求相同数据”相关的问题,事务之间用锁相互隔开。多数主流的数据库支持不一样类型的锁;所以,JDBC API 支持不一样类型的事务,它们由 Connection 对象指派或肯定。
为了在性能与一致性之间寻求平衡才出现了上面的几种级别。事务保护的级别越高,性能损失就越大。
假定您的数据库和 JDBC 驱动程序支持这个特性,则给定一个 Connection 对象,您能够明确地设置想要的事务级别:
conn.setTransactionLevel(TRANSACTION_SERIALIZABLE) ;
能够经过下面的方法肯定当前事务的级别:
int level = conn.getTransactionIsolation();
SavepointManager:管理事务savepoint的编程式API接口。

JDBC定义了SavePoint接口,提供在一个更细粒度的事务控制机制。当设置了一个保存点后,能够rollback到该保存点处的状态,而不是rollback整个事务。Connection接口的setSavepoint和releaseSavepoint方法能够设置和释放保存点。

TransactionStatus:事务状态表现形式。

spring transaction源码分析--事务架构

3.3.3 spring事务实现机制

1 高层

比较好的方式有:1.基于持久层api的模板方法;2.使用具备事务工厂bean的本地ORM api;3使用代理管理本地资源工厂。

2 底层

DataSourceUtils (用做JDBC事务), EntityManagerFactoryUtils (用做JPA事务), SessionFactoryUtils (用做Hibernate事务),PersistenceManagerFactoryUtils (用做JDO事务)等等,

例如:在使用jdbc时,你能够不经过DataSource的getConnection()方法获取connection,而是使用如下方法获取:

Connection conn = DataSourceUtils.getConnection(dataSource);
3 最低层
TransactionAwareDataSourceProxy是事务的最底层,它代理了DataSource,并增长了spring管理事务功能。
参考资料:
1.http://www.educity.cn/rk/457230.html

  1. http://uule.iteye.com/blog/1445678
  2. http://zhxing.iteye.com/blog/368110
相关文章
相关标签/搜索