通常的概念是交易仅与数据库有关。它是由有限的数据库操作序列组成的数据库管理系统执行中的逻辑单元。数据库交易通常包含数据库的读取/写作操作的序列。交易的使用是实现以下两个目的:
当交易提交到数据库管理系统时,数据库管理系统需要确保完成交易中的所有操作,并且结果将永久保存在数据库中。您需要在执行之前返回并返回状态交易;同时,交易对数据库或其他交易的执行没有影响,并且所有交易似乎都在独立运行。
例如,有人使用E-货币在商店中购买100元人民币,包括至少两个操作:至少两个操作:
目前,此交易系统的数据库管理系统必须确保上述两个操作必须在同一时间成功或失败。实际上,失败的风险实际上很高。网络环境,程序代码的漏洞,数据库系统/操作系统的错误,甚至存储介质的错误也可能导致一个失败。因此,这需要数据库管理系统执行恢复的操作失败的事务并将数据库还原为一致数据状态。为了实现将数据库恢复到一致状态的功能,数据库管理系统通常需要维护交易日志以跟踪影响数据库数据的所有操作在交易中。
打开交易和使用语句,您可以使用它。默认情况下,mysql()将自动提交模式(),这意味着,只要执行DML操作语句,MySQL就会立即隐含地提交交易。相反,Oracle需要手动打开/提交交易。
并非数据库的所有操作都需要开始交易。只有那些需要确保一致性的方案才能考虑使用交易。如果您的过程仅执行单个查询,则无需使用交易。这是实时的多阶段。在许多情况下,不需要交易。简而言之,每次您需要在程序中使用交易时,都应对您进行评估,而不是使用不考虑此事的事务,并且不应在程序中泛滥代码。此外,如果交易已打开并且未实时提交,则可能导致数据库事务提交异常,这将导致不可预测的错误。
数据库交易具有以下四个特征,用于称为酸特征:
其中,原子能和孤立更难理解,我们单独解释它。
假设以下操作序列:
确保原子能的含义是,在执行完成后,结果将提交到数据库保存中。如果该过程中的任何操作失败,则必须撤销上一个操作,并且将不保留该操作的数据库,以保证操作的原子性。
根据原子操作序列,假设同时存在另一个操作序列:
目前,为了确保只能同时修改一项交易,您需要在数据a::
交易中获得的互斥锁以更新数据,只有在交易提交或失败后才会发布。在此之前,只能读取其他交易。这是隔离的关键。对于隔离的强度,有以下四个级别:
春季为交易提供了完整的支持。它具有以下好处,可以使用春季来管理事务:
使用@transactions管理交易相对简单。示例如下:
这种写作方式等同于在输入该方法之前使用交易。执行方法后,提交交易。
相反,编程交易的使用必须更加复杂:
如果您需要对程序中的特定异常进行特殊操作,则可以使用尝试...捕捉。请记住,此时调用TransActionStatus的Setrollbackonly方法:
如果您需要获得交易的执行结果,则可以使用:
如何使用@transactional TransactionTemplate优势。利用机会控制交易提交的开放和提交,它可以用较小的粒度控制交易范围,并且更直观的劣势可能会失败。结果,长期交易需要硬编码以控制相同的方法申请交易申请。还有更多的交易操作。交易操作的数量很少在适当的场景中使用。在某些情况下,当某些方案在交易操作上非常频繁时,它非常频繁。尤其是在诸如递归,外部通信等的时间里,它可能会导致长交易。然后,您应该考虑将非交易部分放在其前面,最后在编写数据链接时开始交易。
交易的传播是指应用程序中申请中的服务之间的呼叫。如果呼叫方已创建或尚未创建交易,则将处理服务处理交易的呼叫,如下图所示:
春季指定了7种交易交流特征:
propagation_required如果目前没有交易,请建立新的事务。如果已经有交易,则将添加到此交易中。这是事务通信的默认值。使用当前事务,如果目前尚无交易,请扔Abnormality_requires_new新事务。如果当前交易,则当前事务将悬挂在非交易中的问题_not_supported操作中。交易方法的操作。如果当前有交易,则会引发异常。
由于所有逻辑交易都映射到相同的物理事务,因此,当物理事务中的任何逻辑交易都退缩时,这种物理交易将回滚。以下两项逻辑交易就是示例:
他们的执行过程如下:
如果您使用图来描述:
其中,开始意味着被调用,绿线表示被调用。
需要_new意味着春季将始终创造新的物理事务。在这个隔离级别中,交易可以声明您的超时,仅阅读和隔离级别的设置,而不是继承外部物理事务的特征。相似,我们使用图片来解释这一点:
在这个隔离级别中,每项物理交易都有自己的数据库连接,也就是说,在创建内部物理事务时,它将同时绑定此交易的新数据库连接。当内部物理事务运行时,外部物理事务将被暂停(保持)。提交内部物理事务后,在提交外部时恢复操作,并将执行提交或翻转操作。
此外,在这种沟通水平上,即使内部物理事务正在逐渐回滚,外部物理事务也将正常提交。如果在提交内部物理事务之后将外部物理事务卷回去,那么内部物理事务将不会是任何物理事务的任何物理事务中的任何物理事务。
他们的执行过程如下:
podagation.net itver类似于propagation_required。它仅使用保存点。换句话说,内部逻辑事务可以部分回滚。
SavePoint是数据库交易中的“子交易”。可以将交易卷回到保存点,而不是在SavePoint创建之前更改,而不是滚动整个事务。
propagation_mandator说,必须有物理事务,否则会引发例外:
考虑以下示例:
当调用方法时,由于物理事务已经存在(由passired.equired创建),因此将添加此交易。如果内部事务退后一步,外交将回滚,这是相同的。
propagation_never说,如果有物理事务,那么异常就被抛出了:
其执行过程如下:
当有评论方法时,有必要确保没有打开物理事务。
propagation_not_supported说,如果当前存在物理交易,它将挂起此交易,然后以非交易方式运行该程序。执行完成后,交易将自动恢复。
其执行过程如下:
应该注意的是,即使当前的交易被挂起,也应通过长期运行的任务来避免。这是因为受影响事务的数据库连接仍被激活,这意味着无法重复使用数据库连接池。此连接:
propagation_supports意味着如果存在物理事务,则添加此交易。如果没有物理事务,它将以非交易方式运行。
其执行过程如下:
如果捕获异常:
目前,整个交易仍将回滚。这是因为两个逻辑交易的范围映射到相同的物理交易。
如果删除注释,此时,执行过程如下
了解他们的基本概念以及如何使用它,我们将一起分析春季事务的实施原则。在对实施过程进行正式分析之前,我们首先需要了解一些相对核心的API,这将有助于春季的实施原则对春天的理解。
与交易操作有关的API:
与交易抽象有关的API
与AOP相关的API:
其中,PlatformTransactionManager,TransactionDefinition,TransactionStatus是最重要的。它们之间的关系如下:
PlatformTransActionManager是交易模型的Spring的抽象,它代表了事务的整体执行过程。从基础上讲,交易是在关系数据库中应用的。Spring为交易的读取和写作模型提供了更高的抽象水平,因此可以将其应用于需要数据一致性的任何场景,例如JMX等。Spring将统一这些场景的抽象。这是核心方法提交和回滚。
PlatformTransactionManager的核心方法:
特定方法的逻辑事务以相同的方式提交和回滚也是相应的逻辑交易。
TransActionDefinition是元信息的定义,类似于春季IOC中的Bendefinition。实际上,春季事务的定义是指EJB中的交易的定义。TransactionDefinition的核心方法是:
事务分为逻辑和物理事务。逻辑事务是指代码中交易的操作;物理事务是通过数据库连接获得相关的物理连接和相关的数据库交易。TranSactionStatus用于描述当前逻辑事务的执行。它的核心方法和含义:
从Spring5.2开始,该接口被拆分,并将某些方法放在TransactionExecution中:
@transactional是基于春季AOP实施的,其执行过程大致如下:
为了实施 @transactional,几个关键点是:
首先,让我们观察 @transactional的定义:
如果您需要在Springboot中使用@transactional,我们需要添加@enabletransactionsmanagement注释:
输入与此注释相对应的自动汇编类:
代理模式ProxyTransactionManagementConfiguration的配置类,这是标准的Springboot配置类:
在这里,您将在AnnotationParsers中的AnnotationTributesource中添加一些注释。这是默认的SpringTransactionsNotationParser的示例:
还实施了JTATRANSACTIONNONONORSER和EJB3TRANSACTIONNOTIORSER。这表明春天不仅支持和平。在春季统一的编程模型中,这三个注释可以通用。
接下来,我们查看执行的核心方法,即Transaction Interceptor的调用方法:
输入InvokeTokeNansactions:
在:
输入提交方法:
继续输入ProcessCommit方法:
以文档为例:
可以看出,这是物理事务的提交。类似,回滚也是与数据库的连接,然后调用回滚方法:
在@transactional实施过程的基础上,交易台板的实现更易于理解。TransActionTemplate本质上是模板方法的应用:
从TransactionCallbackWithOutresult的抽象类别可以看出这一点:
在实际的发展中,一旦遇到了一件漫长的事情,一个自然的想法是撤出涉及的部分的部分,并且仅在此方法中添加注释。
这是一个非常普遍的误解。通过对上一篇文章的分析,我们已经知道它是通过AOP实施的。此方法在调用该方法时不会获得事务的功能。仅调用了普通方法,并且将不再具有事务的函数。该解决方案具有以下三种类型。
方法1:添加服务方法:
方法2:如果您不想添加新的服务类,则可以选择将自己注入服务类中。
方法3:通过AOPCONTENT类,代理对象是在服务类中获得的。
私人方法将导致交易失败:
这是因为类方法中有判断。如果目标方法不是公共的,则它将返回null(空),也就是说,它不支持交易。
如果将事务方法定义为最终方法,则还将导致交易不生效,因为CGLIB通过生成sub -categories生成代理类。添加。
当Spring取决于搜索时,它是一个需要用BeanFactory表示的类,也就是说,增加事物的前提是必须通过Spring来管理对象。我们可以使用并等待Bean的依赖性注入。
事物的一个非常重要的特征无法跨线程使用。在以下示例中,尽管我们已经使用了注释,但我们仍然无法管理事务:
这是因为方法和方法在不同的线程中,因此它们获得的数据库连接也不同,这导致了不同交易中的这两种方法。这可以在中国确认。
并非所有存储引擎都支持交易。例如,如果您需要支持交易,则需要将MySQL中的存储引擎替换为存储引擎。
之前,我们对交易的传输特征进行了深入和全面的介绍。如果春天播种
异常的不正确处理也会导致交易失败。例如,开发人员手动处理异常,因此不会将成为代理的方法被捕获为异常,并且自然无法回滚。
此外,由于默认值的异常捕获是和谐的,如果将其他类型的异常抛弃,也将导致交易无法退缩。
因此,您通常可能会看到这样的代码:
长期事务可能会导致以下问题:
尽管@transactional注释更方便,但它将导致整个业务方法处于相同的交易中。粒径相对较厚,无法准确控制交易的范围,这可能导致长交易的出现:
正确的方法是使用可能增长的编程交易:
如果发生长期交易,则可以将查询方法放置在交易之外,因为通常,此类方法不需要交易,例如:
您可以将两种查询方法放在交易执行之外,并且真正需要交易执行的方法,在交易中可以有效地减少交易的粒径。
在业务代码中,其他系统的界面是不可避免的。由于网络不稳定或其他因素,无法保证此远程呼叫的响应时间。如果将远程呼叫代码放置在交易中,则可能会导致长期事务。
正确的方法是将这些操作放在交易之外:
但是,不可能确保数据的一致性。有必要建立重试+补偿机制,以实现数据的最终一致性。
如果需要在交易中处理大量数据,它也将导致大型交易,例如批处理更新和批处理插入。每次数据可以大大减少大型交易的出现。
在每次使用交易之前,我们是否应该认为所有数据库操作都需要在交易中执行?
在上面的示例中,可以在事务中执行操作日志的方法以及统计数量的增加,因为允许操作日志和统计数据与少量数据不一致。
原始:https://juejin.cn/post/7106158888833055353870
