Transactional 注解的应用
什么叫事务?
指要做的或所做的事情。指访问并可能更新数据库中各种数据项的一个程序执行单元。
在关系数据库中,一个事务可以是一条SQL语句、一组SQL语句或者整个程序。
事务通常由高级数据库操纵语言/编程语言书写的用户程序的执行所引起,由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。
事务的传播行为:
所谓事务的传播行为是指,如果
在开始当前事务之前
,
一个事务上下文已经存在
,
此时有若干选项可以指定一个事务性方法的执行行为
。在TransactionDefinition定义中包括了如下7个表示传播行为的常量:
-
TransactionDefinition.PROPAGATION_REQUIRED:
如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。(
默认的传播行为,required
)
例如:方法A调用方法B,它们用同一个事务。(如果B没有事务,它们会用同一个事务)(只要有一个回滚,整体就会回滚) -
TransactionDefinition.PROPAGATION_REQUIRES_NEW:
创建一个新的事务,如果当前存在事务,则把当前事务挂起。
例如:方法A调用方法B,它们用不同的事务。(B不会用A的事务,会新增事务。
“requires_new”
) -
TransactionDefinition.PROPAGATION_SUPPORTS:
如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
例如:
方法A调用方法B
,如果
A没有事务
,那么
B就以非事务执行
。如果
A有事务就以A事务为准
。如果
A没有事务
,那么
B就会以非事务执行
。
(supports)
-
TransactionDefinition.PROPAGATION_NOT_SUPPORTED:
以非事务方式运行,如果当前存在事务,则把当前事务挂起。
例如:方法A调用方法B,方法B会挂起事务A以非事务方式执行。
not_supported
-
TransactionDefinition.PROPAGATION_NEVER:
以非事务方式运行,如果当前存在事务,则抛出异常。
例如:方法A调用方法B,如果方法A没有事务,那么就会抛出异常。
never
-
TransactionDefinition.PROPAGATION_MANDATORY:
如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
mandatory
-
TransactionDefinition.PROPAGATION_NESTED:
如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于
Required
一样。
nested
例如:
方法A中调用了方法B,B中 try catch手动回滚,A不会回滚
。
事务的回滚机制
Spring的AOP即声明式事务管理默认是针对
unchecked exception
回滚。Spring的事务边界是在调用业务方法之前开始的,业务方法执行完毕之后来执行
commit or rollback
(Spring默认取决于是否抛出
runtimeException
)。
如果在方法中有
try{}catch(Exception e){}
处理,那么try里面的代码块就脱离了事务的管理,若要事务生效需要在catch中
throw new RuntimeException (“xxxxxx”);
这一点也是面试中会问到的事务失效的场景。
事务的传播行为示例
一. required
TransactionDefinition.PROPAGATION_REQUIRED:
如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。(
默认的传播行为,required
)
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
public void addUser(){
userDao.addUser();
testService.addTest();
}
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
public void addTest(){
testDao.addTest();
int i = 1/0;
}
REQUIRED
表示在同一个事务:
- addTest异常会使得整个事务回滚,user表和test表都没插入成功。
- addUser异常也会使得事务回滚,user表和test表都没插入成功。
二. requires_new
TransactionDefinition.PROPAGATION_REQUIRES_NEW:
创建一个新的事务,如果当前存在事务,则把当前事务挂起。
例如:方法A调用方法B,它们用不同的事务。(B不会用A的事务,会新增事务。
“requires_new”
)
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
public void addUser(){
userDao.addUser();
testService.addTest();
}
@Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = Exception.class)
public void addTest(){
try {
testDao.addTest();
int i = 1/0;
} catch (Exception e){
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
REQUIRES_NEW表示addTest新创建了一个事务,跟addUser不在同一个事务里。两个事务互不影响。
- addTest异常,进行回滚。addUser没有回滚。user表插入成功,test表插入失败。
- addUser异常,进行回滚。addTest没有回滚。test表插入成功,user表插入失败。
三. supports
TransactionDefinition.PROPAGATION_SUPPORTS:
如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
例如:
方法A调用方法B
,如果
A没有事务
,那么
B就以非事务执行
。如果
A有事务就以A事务为准
。如果
A没有事务
,那么
B就会以非事务执行
。
(supports)
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
public void addUser(){
userDao.addUser();
testService.addTest();
int i = 1/0;
}
@Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
public void addTest(){
try {
testDao.addTest();
} catch (Exception e){
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
如果addUser有事务,那么addTest跟addUser在同一个事务。如果addUser没有事务,那么就以非事务方式运行。
四. not_supported
TransactionDefinition.PROPAGATION_NOT_SUPPORTED:
以非事务方式运行,如果当前存在事务,则把当前事务挂起。
not_supported
例如:方法A调用方法B,方法B会挂起事务A以非事务方式执行。
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
public void addUser(){
userDao.addUser();
testService.addTest();
int i = 1/0;
}
@Transactional(propagation = Propagation.NOT_SUPPORTED,rollbackFor = Exception.class)
public void addTest(){
try {
testDao.addTest();
} catch (Exception e){
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
如果addUser异常,会回滚。addTest不会滚。不管addUser是否有事务,addTest都以非事务方式运行。
五. mandatory
TransactionDefinition.PROPAGATION_MANDATORY:
如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
mandatory
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
public void addUser(){
userDao.addUser();
testService.addTest();
int i = 1/0;
}
@Transactional(propagation = Propagation.MANDATORY,rollbackFor = Exception.class)
public void addTest(){
try {
testDao.addTest();
} catch (Exception e){
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
如果addUser有事务,那么addTest跟addUser在同一个事务。如果addUser没有事务,那么就会报异常:No existing transaction found for transaction marked with propagation ‘mandatory’
六. never
TransactionDefinition.PROPAGATION_NEVER:
以非事务方式运行,如果当前存在事务,则抛出异常。
例如:方法A调用方法B,如果方法A没有事务,那么就会抛出异常。
never
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
public void addUser(){
userDao.addUser();
testService.addTest();
int i = 1/0;
}
@Transactional(propagation = Propagation.NEVER,rollbackFor = Exception.class)
public void addTest(){
try {
testDao.addTest();
} catch (Exception e){
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
如果addUser没有事务,addTest以非事务方式运行。如果addUser有事务,addTest就会报错:Existing transaction found for transaction marked with propagation ‘never’
never和mandatory正好相反。
七. nested
TransactionDefinition.PROPAGATION_NESTED:
如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于
Required
一样。
nested
例如:
方法A中调用了方法B,B中 try catch手动回滚,A不会回滚
。
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
public void addUser(){
userDao.addUser();
testService.addTest();
}
@Transactional(propagation = Propagation.NESTED,rollbackFor = Exception.class)
public void addTest(){
try {
testDao.addTest();
int i = 1/0;
} catch (Exception e){
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
addUser的事务内嵌addTest的事务,如果addUser异常回滚,那么addTest也会回滚。如果addTest回滚,addUser不会回滚。
-
nested和requires_new的不同是:
- nested内层事务回滚不影响外层,外层事务回滚影响内层跟着回滚。
- requires_new外层和内层不是同一个事务,互不影响。外层回滚不影响内层,内层回滚不影响外层。