【轉】SpringBoot 注解事務聲明式事務


文章來源: http://www.cnblogs.com/guozp/articles/7446477.html 

  springboot 對新人來說可能上手比springmvc要快,但是對於各位從springmvc轉戰到springboot的話,有些地方還需要適應下,尤其是xml配置。我個人是比較喜歡注解➕xml是因為看着方便,查找方便,清晰明了。但是xml完全可以使用注解代替,今天就扒一扒springboot中事務使用注解的玩法。

  springboot的事務也主要分為兩大類,一是xml聲明式事務,二是注解事務,注解事務也可以實現類似聲明式事務的方法,關於注解聲明式事務,目前網上搜索不到合適的資料,所以在這里,我將自己查找和總結的幾個方法寫到這里,大家共同探討

    文章來源: http://www.cnblogs.com/guozp/articles/7446477.html 

  • 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 啟動類如下:

  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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事務都可以生效

   

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
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事務都可以生效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
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事務都可以生效

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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(),事物會失效,具體原因暫時不明,如果各位有明白的,可以指點我下。

初始使用:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package  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.interceptor.TransactionInterceptor;
 
/**
  * Created by guozp on 2017/8/28.  ??
  */
@Component
//@Configuration  事務失敗
public  class  TxOtherConfigDefault {
 
    @Autowired
     private  DataSource dataSource;
 
     //@Bean
     //@ConditionalOnMissingBean
     public  PlatformTransactionManager annotationDrivenTransactionManager() {
         return  new  DataSourceTransactionManager(dataSource);
     }*/
 
    @Autowired
    private  DataSourceTransactionManager transactionManager;
 
 
     @Bean
     public  TransactionInterceptor transactionInterceptor() {
         Properties attributes =  new  Properties();
         attributes.setProperty( "get*" "PROPAGATION_REQUIRED" );
         attributes.setProperty( "add*" "PROPAGATION_REQUIRED" );
         attributes.setProperty( "update*" "PROPAGATION_REQUIRED" );
         attributes.setProperty( "delete*" "PROPAGATION_REQUIRED" );
         TransactionInterceptor txAdvice =  new  TransactionInterceptor(transactionManager, attributes);
         return  txAdvice;
     }
 
 
     @Bean
     public  AspectJExpressionPointcut aspectJExpressionPointcut(){
         AspectJExpressionPointcut pointcut =  new  AspectJExpressionPointcut();
         String transactionExecution =  "execution (* com.alibaba.fm9..service.*.*(..))" ;
         pointcut.setExpression(transactionExecution);
         return  pointcut;
     }
 
     @Bean
     public  DefaultPointcutAdvisor defaultPointcutAdvisor(){
         DefaultPointcutAdvisor advisor =  new  DefaultPointcutAdvisor();
         advisor.setPointcut(aspectJExpressionPointcut());
         advisor.setAdvice(transactionInterceptor());
         return  advisor;
     }
}

  

 

后修改如下:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
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,使你的代碼遠離配置文件。

    如果有錯誤的地方,望各位指正。如有其它問題,可以聯系

   文章來源: http://www.cnblogs.com/guozp/articles/7446477.html 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM