SpringBoot 注解事务声明式事务的方式
springboot 对新人来说可能上手比springmvc要快,但是对于各位从springmvc转战到springboot的话,有些地方还需要适应下,尤其是xml配置。我个人是比较喜欢注解➕xml是因为看着方便,查找方便,清晰明了。但是xml完全可以使用注解代替,今天就扒一扒springboot中事务使用注解的玩法。
springboot的事务也主要分为两大类,一是xml声明式事务,二是注解事务,注解事务也可以实现类似声明式事务的方法,关于注解声明式事务,目前网上搜索不到合适的资料,所以在这里,我将自己查找和总结的几个方法写到这里,大家共同探讨
springboot 之 xml事务
可以使用 @importresource("classpath:transaction.xml")
引入该xml的配置,xml的配置如下
<?xml version="1.0" encoding="utf-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemalocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="txmanager" class="org.springframework.jdbc.datasource.datasourcetransactionmanager"> <property name="datasource" ref="datasource" ></property> </bean> <tx:advice id="cftxadvice" transaction-manager="txmanager"> <tx:attributes> <tx:method name="query*" propagation="supports" read-only="true" ></tx:method> <tx:method name="get*" propagation="supports" read-only="true" ></tx:method> <tx:method name="select*" propagation="supports" read-only="true" ></tx:method> <tx:method name="*" propagation="required" rollback-for="exception" ></tx:method> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="allmanagermethod" expression="execution (* com.exmaple.fm..service.*.*(..))" /> <aop:advisor advice-ref="txadvice" pointcut-ref="allmanagermethod" order="0" /> </aop:config> </beans>
springboot 启动类如下:
package com.example.fm; import org.springframework.boot.springapplication; import org.springframework.boot.autoconfigure.springbootapplication; import org.springframework.context.annotation.importresource; @importresource("classpath:transaction.xml") @springbootapplication public class application { public static void main(string[] args) { springapplication.run(application.class, args); } }
启动后即可开启事务,不过项目里导入了xml配置,如果不想导入xml配置,可以使用注解的方式。
springboot 之 注解事务
注解事务讲解之前,需要先了解下spring创建代理的几个类,在spring内部,是通过beanpostprocessor来完成自动创建代理工作的。beanpostprocessor接口的实现只是在applicationcontext初始化的时候才会自动加载,而普通的beanfactory只能通过编程的方式调用之。根据 匹配规则的不同大致分为三种类别:
a、匹配bean的名称自动创建匹配到的bean的代理,实现类beannameautoproxycreator
<bean id="testinterceptor" class="com.example.service.config.testinerceptor”></bean> <bean id="profileautoproxycreator" class="org.springframework.aop.framework. autoproxy.beannameautoproxyproxycreator"> <bean> <property name="beannames"> <list> <value>*service</value> </list> </property> <property name="interceptornames"> <value> testinterceptor </value> </property> </bean>
b、根据bean中的aspectj注解自动创建代理,实现类annotationawareaspectjautoproxycreator
<aop:aspectj-autoproxy proxy-target-class="true"/> <bean id="annotationawareaspectjautoproxycreatortest" class="com.example.service.annotationawareaspectjautoproxycreatortest"/> <aop:config> <aop:aspect ref="annotationawareaspectjautoproxycreatortest"> <aop:around method="process" pointcut="execution (* com.example.service.fm..*.*(..))"/> </aop:aspect> </aop:config>
c、根据advisor的匹配机制自动创建代理,会对容器中所有的advisor进行扫描,自动将这些切面应用到匹配的bean中,实现类defaultadvisorautoproxycreator
接下来开讲注解开启事务的方法:
1、transactional注解事务
需要在进行事物管理的方法上添加注解@transactional,或者偷懒的话直接在类上面添加该注解,使得所有的方法都进行事物的管理,但是依然需要在需要事务管理的类上都添加,工作量比较大,这里只是简单说下,具体的可以google或者bing
2、注解声明式事务
component或configuration中bean的区别,有时间我会专门写一篇来讲解下
a.方式1,这里使用component或configuration事务都可以生效
package com.exmple.service.fm9.config; import java.util.collections; import java.util.hashmap; import java.util.map; import org.aspectj.lang.annotation.aspect; import org.springframework.aop.advisor; import org.springframework.aop.aspectj.aspectjexpressionpointcut; import org.springframework.aop.support.defaultpointcutadvisor; import org.springframework.beans.factory.annotation.autowired; import org.springframework.context.annotation.bean; import org.springframework.context.annotation.configuration; import org.springframework.stereotype.component; import org.springframework.transaction.platformtransactionmanager; import org.springframework.transaction.transactiondefinition; import org.springframework.transaction.interceptor.namematchtransactionattributesource; import org.springframework.transaction.interceptor.rollbackruleattribute; import org.springframework.transaction.interceptor.rulebasedtransactionattribute; import org.springframework.transaction.interceptor.transactionattribute; import org.springframework.transaction.interceptor.transactioninterceptor; /** * created by guozp on 2017/8/28. */ @aspect //@component 事务依然生效 @configuration public class txadviceinterceptor { private static final int tx_method_timeout = 5; private static final string aop_pointcut_expression = "execution (* com.alibaba.fm9..service.*.*(..))"; @autowired private platformtransactionmanager transactionmanager; @bean public transactioninterceptor txadvice() { namematchtransactionattributesource source = new namematchtransactionattributesource(); /*只读事务,不做更新操作*/ rulebasedtransactionattribute readonlytx = new rulebasedtransactionattribute(); readonlytx.setreadonly(true); readonlytx.setpropagationbehavior(transactiondefinition.propagation_not_supported ); /*当前存在事务就使用当前事务,当前不存在事务就创建一个新的事务*/ rulebasedtransactionattribute requiredtx = new rulebasedtransactionattribute(); requiredtx.setrollbackrules( collections.singletonlist(new rollbackruleattribute(exception.class))); requiredtx.setpropagationbehavior(transactiondefinition.propagation_required); requiredtx.settimeout(tx_method_timeout); map<string, transactionattribute> txmap = new hashmap<>(); txmap.put("add*", requiredtx); txmap.put("save*", requiredtx); txmap.put("insert*", requiredtx); txmap.put("update*", requiredtx); txmap.put("delete*", requiredtx); txmap.put("get*", readonlytx); txmap.put("query*", readonlytx); source.setnamemap( txmap ); transactioninterceptor txadvice = new transactioninterceptor(transactionmanager, source); return txadvice; } @bean public advisor txadviceadvisor() { aspectjexpressionpointcut pointcut = new aspectjexpressionpointcut(); pointcut.setexpression(aop_pointcut_expression); return new defaultpointcutadvisor(pointcut, txadvice()); //return new defaultpointcutadvisor(pointcut, txadvice); } }
b.方式1,这里使用component或configuration事务都可以生效
package com.exmple.service.fm9.config; import java.util.collections; import java.util.hashmap; import java.util.map; import org.springframework.aop.aspectj.aspectjexpressionpointcutadvisor; import org.springframework.beans.factory.annotation.autowired; import org.springframework.context.annotation.bean; import org.springframework.context.annotation.configuration; import org.springframework.stereotype.component; import org.springframework.transaction.platformtransactionmanager; import org.springframework.transaction.transactiondefinition; import org.springframework.transaction.interceptor.namematchtransactionattributesource; import org.springframework.transaction.interceptor.rollbackruleattribute; import org.springframework.transaction.interceptor.rulebasedtransactionattribute; import org.springframework.transaction.interceptor.transactionattribute; import org.springframework.transaction.interceptor.transactionattributesource; import org.springframework.transaction.interceptor.transactioninterceptor; /** * created by guozp on 2017/8/29. */ //@component 事务依然生效 @configuration public class txanoconfig { /*事务拦截类型*/ @bean("txsource") public transactionattributesource transactionattributesource(){ namematchtransactionattributesource source = new namematchtransactionattributesource(); /*只读事务,不做更新操作*/ rulebasedtransactionattribute readonlytx = new rulebasedtransactionattribute(); readonlytx.setreadonly(true); readonlytx.setpropagationbehavior(transactiondefinition.propagation_not_supported ); /*当前存在事务就使用当前事务,当前不存在事务就创建一个新的事务*/ //rulebasedtransactionattribute requiredtx = new rulebasedtransactionattribute(); //requiredtx.setrollbackrules( // collections.singletonlist(new rollbackruleattribute(exception.class))); //requiredtx.setpropagationbehavior(transactiondefinition.propagation_required); rulebasedtransactionattribute requiredtx = new rulebasedtransactionattribute(transactiondefinition.propagation_required, collections.singletonlist(new rollbackruleattribute(exception.class))); requiredtx.settimeout(5); map<string, transactionattribute> txmap = new hashmap<>(); txmap.put("add*", requiredtx); txmap.put("save*", requiredtx); txmap.put("insert*", requiredtx); txmap.put("update*", requiredtx); txmap.put("delete*", requiredtx); txmap.put("get*", readonlytx); txmap.put("query*", readonlytx); source.setnamemap( txmap ); return source; } /**切面拦截规则 参数会自动从容器中注入*/ @bean public aspectjexpressionpointcutadvisor pointcutadvisor(transactioninterceptor txinterceptor){ aspectjexpressionpointcutadvisor pointcutadvisor = new aspectjexpressionpointcutadvisor(); pointcutadvisor.setadvice(txinterceptor); pointcutadvisor.setexpression("execution (* com.alibaba.fm9..service.*.*(..))"); return pointcutadvisor; } /*事务拦截器*/ @bean("txinterceptor") transactioninterceptor gettransactioninterceptor(platformtransactionmanager tx){ return new transactioninterceptor(tx , transactionattributesource()) ; } }
c.方式1,这里使用component或configuration事务都可以生效
package com.exmple.service.fm9.config; import java.util.properties; import org.springframework.aop.framework.autoproxy.beannameautoproxycreator; import org.springframework.beans.factory.annotation.autowired; import org.springframework.context.annotation.bean; import org.springframework.context.annotation.configuration; import org.springframework.jdbc.datasource.datasourcetransactionmanager; import org.springframework.stereotype.component; import org.springframework.transaction.interceptor.transactioninterceptor; /** * created by guozp on 2017/8/28. * */ //@component @configuration public class txconfigbeanname { @autowired private datasourcetransactionmanager transactionmanager; // 创建事务通知 @bean(name = "txadvice") public transactioninterceptor getadvisor() throws exception { properties properties = new properties(); properties.setproperty("get*", "propagation_required,-exception,readonly"); properties.setproperty("add*", "propagation_required,-exception,readonly"); properties.setproperty("save*", "propagation_required,-exception,readonly"); properties.setproperty("update*", "propagation_required,-exception,readonly"); properties.setproperty("delete*", "propagation_required,-exception,readonly"); transactioninterceptor tsi = new transactioninterceptor(transactionmanager,properties); return tsi; } @bean public beannameautoproxycreator txproxy() { beannameautoproxycreator creator = new beannameautoproxycreator(); creator.setinterceptornames("txadvice"); creator.setbeannames("*service", "*serviceimpl"); creator.setproxytargetclass(true); return creator; } }
d.方式1,这里使用component或configuration并不是所有事务都可以生效,例如configuration的时候如果打开注释部分的而且不把代码都移动到 defaultpointcutadvisor(),事物会失效,具体原因暂时不明,如果各位有明白的,可以指点我下。
ackage com.alibaba.fm9.config; import java.util.properties; import javax.sql.datasource; import org.springframework.aop.aspectj.aspectjexpressionpointcut; import org.springframework.aop.support.defaultpointcutadvisor; import org.springframework.beans.factory.annotation.autowired; import org.springframework.boot.autoconfigure.condition.conditionalonmissingbean; import org.springframework.context.annotation.bean; import org.springframework.context.annotation.configuration; import org.springframework.jdbc.datasource.datasourcetransactionmanager; import org.springframework.stereotype.component; import org.springframework.transaction.platformtransactionmanager; import org.springframework.transaction.interceptor.transactioninterceptor; /** * created by guozp on 2017/8/28. * ??????? */ @configuration //事务失效,都移动到一个方法不失效 //@component // 事务可行,不用都移动到一个方法 public class txotherconfigdefaultbean { public static final string transactionexecution = "execution (* com.alibaba.fm9..service.*.*(..))"; @autowired private platformtransactionmanager transactionmanager; //@bean //@conditionalonmissingbean //public platformtransactionmanager transactionmanager() { // return new datasourcetransactionmanager(datasource); //} @bean public transactioninterceptor transactioninterceptor() { properties attributes = new properties(); attributes.setproperty("get*", "propagation_required,-exception"); attributes.setproperty("add*", "propagation_required,-exception"); attributes.setproperty("update*", "propagation_required,-exception"); attributes.setproperty("delete*", "propagation_required,-exception"); //transactioninterceptor txadvice = new transactioninterceptor(transactionmanager(), attributes); transactioninterceptor txadvice = new transactioninterceptor(transactionmanager, attributes); return txadvice; } //@bean //public aspectjexpressionpointcut aspectjexpressionpointcut(){ // aspectjexpressionpointcut pointcut = new aspectjexpressionpointcut(); // pointcut.setexpression(transactionexecution); // return pointcut; //} @bean public defaultpointcutadvisor defaultpointcutadvisor(){ //aspectjexpressionpointcut pointcut = new aspectjexpressionpointcut(); //pointcut.setexpression(transactionexecution); //defaultpointcutadvisor advisor = new defaultpointcutadvisor(); //advisor.setpointcut(pointcut); //advisor.setadvice(transactioninterceptor()); aspectjexpressionpointcut pointcut = new aspectjexpressionpointcut(); pointcut.setexpression(transactionexecution); defaultpointcutadvisor advisor = new defaultpointcutadvisor(); advisor.setpointcut(pointcut); properties attributes = new properties(); attributes.setproperty("get*", "propagation_required,-exception"); attributes.setproperty("add*", "propagation_required,-exception"); attributes.setproperty("update*", "propagation_required,-exception"); attributes.setproperty("delete*", "propagation_required,-exception"); transactioninterceptor txadvice = new transactioninterceptor(transactionmanager, attributes); advisor.setadvice(txadvice); return advisor; } }
简单来说,springboot使用上述注解的几种方式开启事物,可以达到和xml中声明的同样效果,但是却告别了xml,使你的代码远离配置文件。
总结
以上所述是小编给大家介绍的springboot 注解事务声明式事务的方式,希望对大家有所帮助