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外层和内层不是同一个事务,互不影响。外层回滚不影响内层,内层回滚不影响外层。