文章來源: 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,使你的代碼遠離配置文件。
如果有錯誤的地方,望各位指正。如有其它問題,可以聯系