IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring事务学习(一) -> 正文阅读

[Java知识库]Spring事务学习(一)

Spring事务管理分类:

编程式事务管理

声明式事务管理

事务步骤

  1. 开启事务
  2. 执行业务逻辑
  3. 出现异常进行回滚
  4. 正常执行则提交事务

编程式事务管理

Spring提供了两种编程式事务管理的方法

  • 使用 TransactionTemplate 或者 TransactionalOperator.
  • 直接实现TransactionManager接口

如果是使用的是命令式编程,Spring推荐使用TransactionTemplate 来完成编程式事务管理,如果是响应式编程,那么使用TransactionalOperator更加合适。

使用TransactionTemplate

使用示例

public class SimpleService implements Service {

    private final TransactionTemplate transactionTemplate;
 
    // 使用构造函数对transactionTemplate进行初始化
    // 需要提供一个transactionManager事务管理器
    public SimpleService(PlatformTransactionManager transactionManager) {
        this.transactionTemplate = new TransactionTemplate(transactionManager);
    }

    public Object someServiceMethod() {
        return transactionTemplate.execute(new TransactionCallback() {
             // the code in this method runs in a transactional context
            public Object doInTransaction(TransactionStatus status) {
                // 这里实现自己的相关业务逻辑
                updateOperation1();
                return resultOfUpdateOperation2();
            }
        });
    }
}

在上面的例子中,显示的使用了TransactionTemplate来完成事务管理,通过实现TransactionCallback回调接口的方式,在doInTransaction方法中完成相关业务逻辑的处理。(回调机制

我们看下TransactionTemplateexecute方法的实现,分析它是如何实现事务管理的:

public <T> T execute(TransactionCallback<T> action) throws TransactionException {
  Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");

  if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
   return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
  }
  else {
   // 1.通过事务管理器开启事务
   TransactionStatus status = this.transactionManager.getTransaction(this);
   T result;
   try {
    // 2.执行传入的业务逻辑
    result = action.doInTransaction(status);
   }
   catch (RuntimeException | Error ex) {
    // 3.出现异常,进行回滚
    rollbackOnException(status, ex);
    throw ex;
   }
   catch (Throwable ex) {
    // 3.出现异常,进行回滚
    rollbackOnException(status, ex);
    throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
   }
   // 4.正常执行完成,提交事务
   this.transactionManager.commit(status);
   return result;
  }
 }

TransactionCallback回调接口

public interface TransactionCallback<T> {

	@Nullable
	T doInTransaction(TransactionStatus status);

在回调方法中,我们可以通过TransactionStatus对象的setRollbackOnly() 方法来 控制事务回滚,如下所示

transactionTemplate.execute(new TransactionCallbackWithoutResult() {

    protected void doInTransactionWithoutResult(TransactionStatus status) {
        try {
            updateOperation1();
            updateOperation2();
        } catch (SomeBusinessException ex) {
            status.setRollbackOnly();
        }
    }
});

TransactionTemplate实质:(模板模式的思想 + 回调的实现方式

Spring 中提供了很多 Template 类,比如,JdbcTemplate、RedisTemplate、RestTemplate。尽管都叫作 xxxTemplate,但它们并非基于模板模式来实现的,而是基于回调来实现的,确切地说应该是同步回调。而同步回调从应用场景上很像模板模式,所以,在命名上,这些类使用 Template(模板)这个单词作为后缀;

为什么不用模板模式的方式实现?

在代码实现上,回调相对于模板模式会更加灵活,主要体现在下面几点。

  • 像 Java 这种只支持单继承的语言,基于模板模式编写的子类,已经继承了一个父类,不再具有继承的能力。
  • 回调可以使用匿名类来创建回调对象,可以不用事先定义类;而模板模式针对不同的实现都要定义不同的子类。
  • 如果某个类中定义了多个模板方法,每个方法都有对应的抽象方法,那即便我们只用到其中的一个模板方法,子类也必须实现所有的抽象方法。而回调就更加灵活,我们只需要往需要用到的模板方法中注入回调对象即可。

实现TransactionManager接口

TransactionTemplate其实也是使用TransactionManager来完成事务管理的,包括开启事务、提交事务、回滚事务;

Spring对事务的抽象

事务处理的基本步骤

  1. 开启事务
  2. 执行业务逻辑
  3. 出现异常进行回滚
  4. 正常执行则提交事务

下面是一个基本的JDBC事务管理代码:

// 开启数据库连接
Connection con = openConnection();
try {
    // 关闭自动提交
    con.setAutoCommit(false);
    // 业务处理
    // ...  
    // 提交事务
    con.commit();
} catch (SQLException | MyException e) {
    // 捕获异常,回滚事务
    try {
        con.rollback();
    } catch (SQLException ex) {
        ex.printStackTrace();
    }
} finally {
    // 关闭连接
    try {
        con.setAutoCommit(true);
        con.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

如果我们需要更换其他数据访问技术,例如Hibernate、MyBatis、JPA等,虽然事务管理的处理步骤都类似,但API却不同,则需使用相应的API来改写。

Spring 事务的关键是对事务策略的抽象,事务策略由 TransactionManager接口定义

  1. ReactiveTransactionManager,响应式编程事务管理使用这个接口

  2. PlatformTransactionManager,命令式编程事务管理使用这个接口

Spring把通用的事务处理过程给抽象出来,对外屏蔽 事务底层的具体实现逻辑 ,通过跨不同事务 API 的一致编程模型,使其可以在任何底层事务基础架构上运行;

在Spring事务中,对事务策略抽象的 核心接口是PlatformTransactionManager,也叫事务管理器,其定义如下:

PlatformTransactionManager

接口定义

public interface PlatformTransactionManager extends TransactionManager {
 	// 获取事务(开启新的事务或者获取已经存在的事务)
    TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
 
    // 提交事务
    void commit(TransactionStatus status) throws TransactionException;
 
    // 回滚事务
    void rollback(TransactionStatus status) throws TransactionException;
}

PlatformTransactionManager是Spring 命令式编程事务管理的核心接口,定义了完成一个事务所必须的三个步骤,也就是定义了事务实现的规范;

  • 开启事务
  • 提交事务
  • 回滚事务

AbstractPlatformTransactionManagerPlatformTransactionManager接口的的实现,这个类是Spring提供的一个事务管理的基类,提供了事务管理的模板,它实现了Spring事务管理的一个标准流程。(模板方法模式)

  1. 判断当前是否已经存在一个事务

  2. 应用合适的事务传播行为

  3. 在必要的时候挂起/恢复事务

  4. 提交时检查事务是否被标记成为rollback-only,控制 执行真实的回滚/还是执行真实的提交操作

  5. 触发注册的同步回调

AbstractPlatformTransactionManager这个模板类中 ,实现了通用的事务处理逻辑 (实现了 开启事务、提交事务、回滚事务 这三个模板方法),并且在这三个模板方法中 将底层具体的实现定义为抽象方法 交由 子类自己去具体实现;

以commit 方法为例,我们来看下AbstractPlatformTransactionManager这个模板类是怎么处理的;

public final void commit(TransactionStatus status) throws TransactionException {
    // 1.检查事务是否已完成
    if (status.isCompleted()) {
        throw new IllegalTransactionStateException(
            "Transaction is already completed - do not call commit or rollback more than once per transaction");
    }

    // 2.检查事务是否需要回滚(局部事务回滚)
    DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
    if (defStatus.isLocalRollbackOnly()) {
        if (defStatus.isDebug()) {
            logger.debug("Transactional code has requested rollback");
        }
        processRollback(defStatus, false);
        return;
    }

    // 3.检查事务是否需要回滚(全局事务回滚)
    if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
        if (defStatus.isDebug()) {
            logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
        }
        processRollback(defStatus, true);
        return;
    }
    
    // 4.提交事务
    processCommit(defStatus);
}

commit这个模板方法中定义了事务提交的基本逻辑,通过查看status的事务状态来决定抛出异常还是回滚,或是提交。其中的processRollbackprocessCommit方法也是模板方法,进一步定义了回滚、提交的处理逻辑。

processCommit方法为例,具体的提交操作将由抽象方法doCommit完成。

	private void processCommit(DefaultTransactionStatus status) throws TransactionException {
		try {
			boolean beforeCompletionInvoked = false;

			try {
				boolean unexpectedRollback = false;
				prepareForCommit(status);
				triggerBeforeCommit(status);
				triggerBeforeCompletion(status);
				beforeCompletionInvoked = true;
				
				if (status.hasSavepoint()) {
					if (status.isDebug()) {
						logger.debug("Releasing transaction savepoint");
					}
					unexpectedRollback = status.isGlobalRollbackOnly();
					status.releaseHeldSavepoint();
				}
				else if (status.isNewTransaction()) {
					if (status.isDebug()) {
						logger.debug("Initiating transaction commit");
					}
					unexpectedRollback = status.isGlobalRollbackOnly();
					doCommit(status);
				}
				else if (isFailEarlyOnGlobalRollbackOnly()) {
					unexpectedRollback = status.isGlobalRollbackOnly();
				}

				// Throw UnexpectedRollbackException if we have a global rollback-only
				// marker but still didn't get a corresponding exception from commit.
				if (unexpectedRollback) {
					throw new UnexpectedRollbackException(
							"Transaction silently rolled back because it has been marked as rollback-only");
				}
			}
	}
protected abstract void doCommit(DefaultTransactionStatus status) throws TransactionException;

doCommit的具体实现取决于具体的数据访问技术。我们看下JDBC相应的具体实现类DataSourceTransactionManager中的doCommit实现。

protected void doCommit(DefaultTransactionStatus status) {
    // 获取status中的事务对象    
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
    // 通过事务对象获得数据库连接对象
    Connection con = txObject.getConnectionHolder().getConnection();
    if (status.isDebug()) {
        logger.debug("Committing JDBC transaction on Connection [" + con + "]");
    }
    try {
        // 执行commit
        con.commit();
    }
    catch (SQLException ex) {
        throw new TransactionSystemException("Could not commit JDBC transaction", ex);
    }
}

在整个事务处理的过程中,通用的事务处理过程都被抽象到AbstractPlatformTransactionManager中实现了,

这些公共的事务处理过程是是与 具体事务管理器无关的,事务底层的具体实现逻辑封装在了具体的事务管理器中(比如DataSourceTransactionManagerHibernateTransactionManager

用Spring事务API改写后的事务管理代码:

// 获得事务管理器
PlatformTransactionManager txManager = getPlatformTransactionManager();
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// 指定事务元信息
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// 获得事务
TransactionStatus status = txManager.getTransaction(def);
try {
    // 业务处理
}
catch (MyException ex) {
    // 捕获异常,回滚事务
    txManager.rollback(status);
    throw ex;
}
// 提交事务
txManager.commit(status);

无论是使用JDBC、Hibernate还是MyBatis,我们只需要传给txManager相应的具体实现就可以在多种数据访问技术中切换。

Spring事务通过PlatformTransactionManagerTransactionDefinitionTransactionStatus接口统一事务管理API,并结合模板方法和策略模式决定具体实现。

小结

Spring把通用的事务处理过程给抽象出来, 并且通过定义接口的方式屏蔽事务底层的具体实现逻辑, 应用策略模式 根据具体使用的数据访问技术 来 决定 具体的事务管理API

Spring 通过 提供 跨不同事务 API 的一致编程模型,使其可以在任何底层事务基础架构上运行,例如 Java 事务 API (JTA)、JDBC、Hibernate 和 Java Persistence API (JPA)。

参考:

https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-08-10 23:04:10  更:2021-08-10 23:04:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 5:53:31-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码