Spring中@Transactional用法详细介绍
Spring中@Transactional用法详细介绍
引言:在spring中@Transactional提供一种控制事务管理的快捷手段,但是很多人都只是@Transactional简单使用,并未深入了解,其各个配置项的使用方法,本文将深入讲解各个配置项的使用。
1. @Transactional的定义
Spring中的@Transactional基于动态代理的机制,提供了一种透明的事务管理机制,方便快捷解决在开发中碰到的问题。在现实中,实际的问题往往比我们预期的要复杂很多,这就要求对@Transactional有深入的了解,以来应对复杂问题。
首先我们来看看@Transactional的代码定义:
@Target({ElementType.METHOD,ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public@interfaceTransactional{ /** *Aqualifiervalueforthespecifiedtransaction. *<p>Maybeusedtodeterminethetargettransactionmanager, *matchingthequalifiervalue(orthebeanname)ofaspecific *{@linkorg.springframework.transaction.PlatformTransactionManager} *beandefinition. */ Stringvalue()default""; /** *Thetransactionpropagationtype. *Defaultsto{@linkPropagation#REQUIRED}. *@seeorg.springframework.transaction.interceptor.TransactionAttribute#getPropagationBehavior() */ Propagationpropagation()defaultPropagation.REQUIRED; /** *Thetransactionisolationlevel. *Defaultsto{@linkIsolation#DEFAULT}. *@seeorg.springframework.transaction.interceptor.TransactionAttribute#getIsolationLevel() */ Isolationisolation()defaultIsolation.DEFAULT; /** *Thetimeoutforthistransaction. *Defaultstothedefaulttimeoutoftheunderlyingtransactionsystem. *@seeorg.springframework.transaction.interceptor.TransactionAttribute#getTimeout() */ inttimeout()defaultTransactionDefinition.TIMEOUT_DEFAULT; /** *{@codetrue}ifthetransactionisread-only. *Defaultsto{@codefalse}. *<p>Thisjustservesasahintfortheactualtransactionsubsystem; *itwill<i>notnecessarily</i>causefailureofwriteaccessattempts. *Atransactionmanagerwhichcannotinterprettheread-onlyhintwill *<i>not</i>throwanexceptionwhenaskedforaread-onlytransaction. *@seeorg.springframework.transaction.interceptor.TransactionAttribute#isReadOnly() */ booleanreadOnly()defaultfalse; /** *Defineszero(0)ormoreexception{@linkClassclasses},whichmustbea *subclassof{@linkThrowable},indicatingwhichexceptiontypesmustcause *atransactionrollback. *<p>Thisisthepreferredwaytoconstructarollbackrule,matchingthe *exceptionclassandsubclasses. *<p>Similarto{@linkorg.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(Classclazz)} */ Class<?extendsThrowable>[]rollbackFor()default{}; /** *Defineszero(0)ormoreexceptionnames(forexceptionswhichmustbea *subclassof{@linkThrowable}),indicatingwhichexceptiontypesmustcause *atransactionrollback. *<p>Thiscanbeasubstring,withnowildcardsupportatpresent. *Avalueof"ServletException"wouldmatch *{@linkjavax.servlet.ServletException}andsubclasses,forexample. *<p><b>NB:</b>Considercarefullyhowspecificthepatternis,andwhether *toincludepackageinformation(whichisn'tmandatory).Forexample, *"Exception"willmatchnearlyanything,andwillprobablyhideotherrules. *"java.lang.Exception"wouldbecorrectif"Exception"wasmeanttodefine *aruleforallcheckedexceptions.Withmoreunusual{@linkException} *namessuchas"BaseBusinessException"thereisnoneedtouseaFQN. *<p>Similarto{@linkorg.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(StringexceptionName)} */ String[]rollbackForClassName()default{}; /** *Defineszero(0)ormoreexception{@linkClassClasses},whichmustbea *subclassof{@linkThrowable},indicatingwhichexceptiontypesmust<b>not</b> *causeatransactionrollback. *<p>Thisisthepreferredwaytoconstructarollbackrule,matchingthe *exceptionclassandsubclasses. *<p>Similarto{@linkorg.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(Classclazz)} */ Class<?extendsThrowable>[]noRollbackFor()default{}; /** *Defineszero(0)ormoreexceptionnames(forexceptionswhichmustbea *subclassof{@linkThrowable})indicatingwhichexceptiontypesmust<b>not</b> *causeatransactionrollback. *<p>Seethedescriptionof{@link#rollbackForClassName()}formoreinfoonhow *thespecifiednamesaretreated. *<p>Similarto{@linkorg.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(StringexceptionName)} */ String[]noRollbackForClassName()default{}; }
基于源代码,我们可以发现在@Transactional,原来有这么多的属性可以进行配置,从而达到复杂应用控制的目的。具体各个属性的用法和作用,将在本文的后面逐一进行讲解和说明。
2. 使用@Transactional的Spring配置
为了使用基于@Transactional的事务管理,需要在Spring中进行如下的配置:
<beans:beanid="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <beans:propertyname="dataSource"ref="dataSource"/> <beans:propertyname="entityManagerFactory"ref="entityManagerFactory"/> </beans:bean> <!--声明使用注解式事务--> <tx:annotation-driventransaction-manager="transactionManager"/>
dataSource是在Spring配置文件中定义的数据源的对象实例,EntityManagerFactory是基于JPA使用的实体类管理器:org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean。这些都是用来配置与数据库的连接信息,本质上,@Transactional使用了JDBC的事务来进行事务控制的。
<annotation-driven>标签的声明,则是在Spring内部启用@Transactional来进行事务管理,类似开关之类的声明。
3. @Transactional之value
value这里主要用来指定不同的事务管理器;主要用来满足在同一个系统中,存在不同的事务管理器。比如在Spring中,声明了两种事务管理器txManager1,txManager2.
然后,用户可以根据这个参数来根据需要指定特定的txManager.
那有同学会问什么情况下会存在多个事务管理器的情况呢?比如在一个系统中,需要访问多个数据源或者多个数据库,则必然会配置多个事务管理器的。
4. @Transactional之propagation
Propagation支持7种不同的传播机制:
REQUIRED
业务方法需要在一个事务中运行,如果方法运行时,已处在一个事务中,那么就加入该事务,否则自己创建一个新的事务.这是spring默认的传播行为.。
SUPPORTS:
如果业务方法在某个事务范围内被调用,则方法成为该事务的一部分,如果业务方法在事务范围外被调用,则方法在没有事务的环境下执行。
MANDATORY:
只能在一个已存在事务中执行,业务方法不能发起自己的事务,如果业务方法在没有事务的环境下调用,就抛异常
REQUIRES_NEW
业务方法总是会为自己发起一个新的事务,如果方法已运行在一个事务中,则原有事务被挂起,新的事务被创建,直到方法结束,新事务才结束,原先的事务才会恢复执行.
NOT_SUPPORTED
声明方法需要事务,如果方法没有关联到一个事务,容器不会为它开启事务.如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后,原先的事务便会恢复执行.
NEVER:
声明方法绝对不能在事务范围内执行,如果方法在某个事务范围内执行,容器就抛异常.只有没关联到事务,才正常执行.
NESTED:
如果一个活动的事务存在,则运行在一个嵌套的事务中.如果没有活动的事务,则按REQUIRED属性执行.它使用了一个单独的事务,这个事务拥有多个可以回滚的保证点.内部事务回滚不会对外部事务造成影响,它只对DataSourceTransactionManager事务管理器起效.
其实大家最感到困惑的是REQUIRED_NEW和NESTED两种不同的传播机制,功能类似,都涉及到了事务嵌套的问题,那两者有何区别呢?该如何正确使用这两种模式呢?
以下是摘自Spring的文档:
PROPAGATION_REQUIRES_NEW:usesacompletelyindependenttransactionfor eachaffectedtransactionscope.Inthatcase,theunderlyingphysical transactionsaredifferentandhencecancommitorrollbackindependently, withanoutertransactionnotaffectedbyaninnertransaction'srollbackstatus.
内部的事务独立运行,在各自的作用域中,可以独立的回滚或者提交;而外部的事务将不受内部事务的回滚状态影响。
ROPAGATION_NESTED:usesasinglephysicaltransactionwithmultiple savepointsthatitcanrollbackto.Suchpartialrollbacksallowan innertransactionscopetotriggerarollbackforitsscope,withtheouter transactionbeingabletocontinuethephysicaltransactiondespitesomeoperations havingbeenrolledback.ThissettingistypicallymappedontoJDBCsavepoints,sowill onlyworkwithJDBCresourcetransactions.
NESTED的事务,基于单一的事务来管理,提供了多个保存点。这种多个保存点的机制允许内部事务的变更触发外部事务的回滚。而外部事务在混滚之后,仍能继续进行事务处理,即使部分操作已经被混滚。由于这个设置基于JDBC的保存点,所以只能工作在JDBC的机制智商。
由此可知,两者都是事务嵌套,不同之处在于,内外事务之间是否存在彼此之间的影响;NESTED之间会受到影响,而产生部分回滚,而REQUIRED_NEW则是独立的。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!