0%

注解Transactional注意事项

事务管理可以分为编程式事务管理,声明式事务管理两类;

声明式事务管理中有一只简便的事务管理方式:基于Transactional注解的事务管理方式。

但是使用@Transactional时有些必须注意的细节,总结如下:

网络图片

Transactional

这里直接先上源码:注释描述的很清楚,可以直接生吃;

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149

package org.springframework.transaction.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.core.annotation.AliasFor;
import org.springframework.transaction.TransactionDefinition;

/**
* Describes transaction attributes on a method or class.
*
* <p>This annotation type is generally directly comparable to Spring's
* {@link org.springframework.transaction.interceptor.RuleBasedTransactionAttribute}
* class, and in fact {@link AnnotationTransactionAttributeSource} will directly
* convert the data to the latter class, so that Spring's transaction support code
* does not have to know about annotations. If no rules are relevant to the exception,
* it will be treated like
* {@link org.springframework.transaction.interceptor.DefaultTransactionAttribute}
* (rolling back on runtime exceptions).
*
* <p>For specific information about the semantics of this annotation's attributes,
* consult the {@link org.springframework.transaction.TransactionDefinition} and
* {@link org.springframework.transaction.interceptor.TransactionAttribute} javadocs.
*
* @author Colin Sampaleanu
* @author Juergen Hoeller
* @author Sam Brannen
* @since 1.2
* @see org.springframework.transaction.interceptor.TransactionAttribute
* @see org.springframework.transaction.interceptor.DefaultTransactionAttribute
* @see org.springframework.transaction.interceptor.RuleBasedTransactionAttribute
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {

/**
* Alias for {@link #transactionManager}.
* @see #transactionManager
*/
@AliasFor("transactionManager")
String value() default "";

/**
* A <em>qualifier</em> value for the specified transaction.
* <p>May be used to determine the target transaction manager,
* matching the qualifier value (or the bean name) of a specific
* {@link org.springframework.transaction.PlatformTransactionManager}
* bean definition.
* @since 4.2
* @see #value
*/
@AliasFor("value")
String transactionManager() default "";

/**
* The transaction propagation type.
* <p>Defaults to {@link Propagation#REQUIRED}.
* @see org.springframework.transaction.interceptor.TransactionAttribute#getPropagationBehavior()
*/
Propagation propagation() default Propagation.REQUIRED;

/**
* The transaction isolation level.
* <p>Defaults to {@link Isolation#DEFAULT}.
* @see org.springframework.transaction.interceptor.TransactionAttribute#getIsolationLevel()
*/
Isolation isolation() default Isolation.DEFAULT;

/**
* The timeout for this transaction.
* <p>Defaults to the default timeout of the underlying transaction system.
* @see org.springframework.transaction.interceptor.TransactionAttribute#getTimeout()
*/
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;

/**
* {@code true} if the transaction is read-only.
* <p>Defaults to {@code false}.
* <p>This just serves as a hint for the actual transaction subsystem;
* it will <i>not necessarily</i> cause failure of write access attempts.
* A transaction manager which cannot interpret the read-only hint will
* <i>not</i> throw an exception when asked for a read-only transaction.
* @see org.springframework.transaction.interceptor.TransactionAttribute#isReadOnly()
*/
boolean readOnly() default false;

/**
* Defines zero (0) or more exception {@link Class classes}, which must be
* subclasses of {@link Throwable}, indicating which exception types must cause
* a transaction rollback.
* <p>This is the preferred way to construct a rollback rule (in contrast to
* {@link #rollbackForClassName}), matching the exception class and its subclasses.
* <p>Similar to {@link org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(Class clazz)}
* @see #rollbackForClassName
*/
Class<? extends Throwable>[] rollbackFor() default {};

/**
* Defines zero (0) or more exception names (for exceptions which must be a
* subclass of {@link Throwable}), indicating which exception types must cause
* a transaction rollback.
* <p>This can be a substring of a fully qualified class name, with no wildcard
* support at present. For example, a value of {@code "ServletException"} would
* match {@link javax.servlet.ServletException} and its subclasses.
* <p><b>NB:</b> Consider carefully how specific the pattern is and whether
* to include package information (which isn't mandatory). For example,
* {@code "Exception"} will match nearly anything and will probably hide other
* rules. {@code "java.lang.Exception"} would be correct if {@code "Exception"}
* were meant to define a rule for all checked exceptions. With more unusual
* {@link Exception} names such as {@code "BaseBusinessException"} there is no
* need to use a FQN.
* <p>Similar to {@link org.springframework.transaction.interceptor.RollbackRuleAttribute#RollbackRuleAttribute(String exceptionName)}
* @see #rollbackFor
*/
String[] rollbackForClassName() default {};

/**
* Defines zero (0) or more exception {@link Class Classes}, which must be
* subclasses of {@link Throwable}, indicating which exception types must
* <b>not</b> cause a transaction rollback.
* <p>This is the preferred way to construct a rollback rule (in contrast
* to {@link #noRollbackForClassName}), matching the exception class and
* its subclasses.
* <p>Similar to {@link org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(Class clazz)}
* @see #noRollbackForClassName
*/
Class<? extends Throwable>[] noRollbackFor() default {};

/**
* Defines zero (0) or more exception names (for exceptions which must be a
* subclass of {@link Throwable}) indicating which exception types must <b>not</b>
* cause a transaction rollback.
* <p>See the description of {@link #rollbackForClassName} for further
* information on how the specified names are treated.
* <p>Similar to {@link org.springframework.transaction.interceptor.NoRollbackRuleAttribute#NoRollbackRuleAttribute(String exceptionName)}
* @see #noRollbackFor
*/
String[] noRollbackForClassName() default {};

}

直接取出关键的内容:

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
// 注解可以作用在 方法 和 类  上
@Target({ElementType.METHOD, ElementType.TYPE})
// 注解的声明周期 是运行时有效
@Retention(RetentionPolicy.RUNTIME)
// 支持继承
@Inherited
@Documented
public @interface Transactional {
// value 是 transactionManager 属性的别名
@AliasFor("transactionManager")
String value() default "";
// transactionManager 给注解取一个名字,类似容器类中的ID
@AliasFor("value")
String transactionManager() default "";
// 用于设置:事务的传播方式
Propagation propagation() default Propagation.REQUIRED;
// 用于设置:事务的隔离级别
Isolation isolation() default Isolation.DEFAULT;
// 用于设置:事务的超时时间
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
// 用于设置:事务的可读性
boolean readOnly() default false;
// 用于设置:事务的发送异常时 ,事务回滚
Class<? extends Throwable>[] rollbackFor() default {};
// 用于设置:事务的发送异常时 ,事务回滚
String[] rollbackForClassName() default {};
// 用于设置:即使事务的发送异常时 ,事务不回滚
Class<? extends Throwable>[] noRollbackFor() default {};
// 用于设置:即使事务的发送异常时 ,事务不回滚
String[] noRollbackForClassName() default {};
}

propagation 传播方式

事务的传播方式有如下几种:具体可以查看org.springframework.transaction.annotation.Propagation

TransactionDefinition.PROPAGATION_REQUIRED:

默认的传播方式:如果当前存在事务,则加入当前事务;如果不存在这新建一个事务;

TransactionDefinition.PROPAGATION_SUPPORTS:

如果当前存在事务,则加入当前事务;如果不存在则以非事务(PROPAGATION_NOT_SUPPORTED)方式执行,PROPAGATION_NOT_SUPPORTED 方式后面有介绍;

TransactionDefinition.PROPAGATION_MANDATORY:

如果当前存在事务,则加入当前事务;如果不存在则抛出异常;

TransactionDefinition.PROPAGATION_REQUIRES_NEW:

如果当前存在事务,则暂停当前事务;如果不存在,则创建新的事务;

TransactionDefinition.PROPAGATION_NOT_SUPPORTED:

以非事务(non-transactionally)方式执行,如果当前存在事务,则暂停当前事务;

TransactionDefinition.PROPAGATION_NEVER:

以非事务(non-transactionally)方式执行,如果当前存在事务,则抛出异常;

TransactionDefinition.PROPAGATION_NESTED:

如果当前存在事务,则创建一个事务作为当前事务的嵌套事务执行,如果当前没有事务,就以PROPAGATION_REQUIRED方式执行;

non-transactionally:非事务方式运行,即不加入事务管理;

isolation 隔离级别

事务的隔离级别有如下几种类型:目的是为了解决数据查询时出现的:数据更新丢失,脏读,虚读(重复读),幻读 问题;
为了方便记忆,可以直接从类型命名上理解:

DEFAULT(TransactionDefinition.ISOLATION_DEFAULT):

默认的;可能出现上面所有的问题;

READ_UNCOMMITTED(TransactionDefinition.ISOLATION_READ_UNCOMMITTED):

从字面理解:可以读到,未提交的内容;

允许脏读取,虚读,幻读,但不允许更新丢失;

脏读(事务A读取到了事务B未提交的内容);

如果一个事务已经开始写数据,另外一个事务将不允许同时进行写操作,但允许其他事务读此行数据。

READ_COMMITTED(TransactionDefinition.ISOLATION_READ_COMMITTED):

从字面理解:可以读到,已提交的内容;

允许虚读,幻读,但不允许脏读取。

虚读(事务A两次读取,读取到数据行内容不一样,因为事务B在更新数据行);

读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行;

REPEATABLE_READ(TransactionDefinition.ISOLATION_REPEATABLE_READ):

从字面理解:重复读,可能读到不一样的数据 ;

禁止虚读和脏读,但是可能出现幻读。

幻读(事务A两次读取,读取到内容条数不一样,因为事务B在更新数据,导致符合条件的数据行增多、减少);

读取数据的事务将会禁止写事务(但允许读事务),写事务时禁止任何其他事务;

SERIALIZABLE(TransactionDefinition.ISOLATION_SERIALIZABLE):

提供严格的事务隔离。它要求事务序列化执行,隔离级别最高;

timeout

设置事务超时时间

readOnly 只读模式

事务是否只读

rollback 方式

rollbackXXX ,noRollbackXXX 各有两种方式设置回顾条件;这里只对rollbackXXX总结,noRollbackXXX同理:

rollbackFor 属性:通过class 来设置回滚条件;

rollbackForClassName 属性 :通过ClassName来设置回滚条件;

@Transactional细节

@Transactional Target

@Transactional 可以作用在Class,Mothed上,但是不建议作用在Interface上;

@Transactional 只能作用在public的mothed上,否则事务不会生效,原因是因为AOP的切点必须是public的;

@Transactional Exception

Transactional 默认情况下只会对unchecked exceptions进行事务回滚。如果是checked exceptions将不会执行事务回滚;

checked exceptions异常执行回滚: 需要通过rollbackXXX ,noRollbackXXX设置

unchecked exceptions:Error 和 RuntimeException 及其子类属于unchecked exception;这种异常不需要手动捕获;

checked exceptions: 这种异常需要手动捕获,需要try catch();

GitHub登录不了?信任该网站之后再登录。