Spring 的事务管理

发布于 2024-10-24 23:21:08 字数 4194 浏览 2 评论 0

事物的特性(ACID)

  1. 原子性: 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
  2. 一致性: 执行事务前后,数据保持一致;
  3. 隔离性: 并发访问数据库时,一个用户的事物不被其他事物所干扰,各并发事务之间数据库是独立的;
  4. 持久性: 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。

事务管理 :按照给定的事务规则来执行提交或者回滚操作

Spring 并不直接管理事务,而是提供了多种事务管理器。

Spring 事务管理器的接口是: org.springframework.transaction.PlatformTransactionManager ,通过这个接口,Spring 为各个平台如 JDBC、Hibernate 等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。

PlatformTransactionManager 接口中定义了三个方法:

Public interface PlatformTransactionManager()...{  
  // Return a currently active transaction or create a new one, according to the specified propagation behavior(根据指定的传播行为,返回当前活动的事务或创建一个新事务。)
  TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; 
  // Commit the given transaction, with regard to its status(使用事务目前的状态提交事务)
  Void commit(TransactionStatus status) throws TransactionException;  
  // Perform a rollback of the given transaction(对执行的事务进行回滚)
  Void rollback(TransactionStatus status) throws TransactionException;  
} 

比如我们在使用 JDBC 或者 iBatis(就是 Mybatis)进行数据持久化操作时,我们的 xml 配置通常如下:

<!-- 事务管理器 -->
<bean id="transactionManager"
  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <!-- 数据源 -->
  <property name="dataSource" ref="dataSource" />
</bean>

事务管理器接口 PlatformTransactionManager 通过 getTransaction(TransactionDefinition definition) 方法来得到一个事务,
这个方法里面的参数是 TransactionDefinition 类 ,这个类就定义了一些基本的事务属性。

public interface TransactionDefinition {
  // 返回事务的传播行为
  int getPropagationBehavior(); 
  // 返回事务的隔离级别,事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据
  int getIsolationLevel(); 
  // 返回事务必须在多少秒内完成
  //返回事务的名字
  String getName();
  int getTimeout();  
  // 返回是否优化为只读事务。
  boolean isReadOnly();
} 

并发事务带来的问题

在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对统一数据进行操作)。并发虽然是必须的,但可能会导致一下的问题。

脏读(Dirty read): 当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。

丢失修改(Lost to modify): 指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。
例如:事务 1 读取某表中的数据 A=20,事务 2 也读取 A=20,事务 1 修改 A=A-1 ,事务 2 也修改 A=A-1 ,最终结果 A=19,事务 1 的修改被丢失。

不可重复读(Unrepeatableread): 指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。

幻读(Phantom read): 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。

不可重复度和幻读区别:

不可重复读的重点是修改,幻读的重点在于新增或者删除。

隔离级别

TransactionDefinition 接口中定义了五个表示隔离级别的常量:TransactionDefinition.ISOLATION_DEFAULT:默认的隔离级别

事务传播行为

为了解决业务层方法之间互相调用的事务问题)

  1. TransactionDefinition.PROPAGATION_REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
  2. TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
  3. TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)

事务只读属性

对事物资源是否执行只读操作

事务的只读属性是指,对事务性资源进行只读操作或者是读写操作。所谓事务性资源就是指那些被事务管理的资源,
比如数据源、 JMS 资源,以及自定义的事务性资源等等。
如果确定只对事务性资源进行只读操作,那么我们可以将事务标志为只读的,以提高事务处理的性能。在 TransactionDefinition 中以 boolean 类型来表示该事务是否只读。

回滚规则(定义事务回滚规则)

但是你可以声明事务在遇到特定的检查型异常时像遇到运行期异常那样回滚。同样,你还可以声明事务遇到特定的异常不回滚,即使这些异常是运行期异常。

TransactionStatus 接口介绍

TransactionStatus 接口用来记录事务的状态 该接口定义了一组方法,用来获取或判断事务的相应状态信息。

PlatformTransactionManager.getTransaction(…) ​ 方法返回一个 TransactionStatus 对象。
返回的 TransactionStatus 对象可能代表一个新的或已经存在的事务(如果在当前调用堆栈有一个符合条件的事务)。

TransactionStatus 接口接口内容如下:

public interface TransactionStatus{
  boolean isNewTransaction(); // 是否是新的事物
  boolean hasSavepoint(); // 是否有恢复点
  void setRollbackOnly();  // 设置为只回滚
  boolean isRollbackOnly(); // 是否为只回滚
  boolean isCompleted; // 是否已完成
} 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

往日情怀

暂无简介

0 文章
0 评论
22 人气
更多

推荐作者

月光色

文章 0 评论 0

咆哮

文章 0 评论 0

痞味浪人

文章 0 评论 0

宁涵

文章 0 评论 0

军弟

文章 0 评论 0

临走之时

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文