spring 事务总结
前置条件
表Teacher 别名 A ,表Student 别名 B 分别插入。
A中启动事务,B中不启动事务 testDemo01调用方法开启事务
testDemo01开启事务,A中insert中开启事务,调用执行,A中执行成功,B中执行出现异常,AB事务回滚。
//A 表处理
@Override
@Transactional
public int insert(Teacher record) {
log.info("teacher 插入开始....");
return teacherDAO.insert(record);
}
//B表处理
@Override
public int insert(Student record) {
log.info("Student 插入处理....");
return studentDAO.insert(record);
}
//调用方法处理
@Transactional
public void testDemo01() throws Exception{
teacherService.insert(getTeacherEntity(2));
studentService.insert(getStudentEntity(2));
}
A,B调用顺序调整。testDemo01开启事务,A中insert中开启事务,调用执行,A中执行异常,B中执行成功,AB事务回滚。
@Transactional
public void testDemo01() throws Exception{
studentService.insert(getStudentEntity(2));
teacherService.insert(getTeacherEntity(2));
}
//A
@Override
@Transactional
public int insert(Teacher record) {
log.info("teacher 插入开始....");
int ss = teacherDAO.insert(record);
int i = 1 / 0;
return ss;
}
A中事务开启新事务,调用后A调用异常,B中正常,A事务回滚,B事务不回滚
//A
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public int insert(Teacher record) throws Exception{
log.info("teacher 插入开始....");
int ss = teacherDAO.insert(record);
int i = 1 / 0;
return ss;
}
A中开启事务,并使用try catch 将异常抓取。结果 A插入成功,B插入成功。事务没有执行会滚。
//调用方法
@Transactional
public void testDemo01() throws Exception{
studentService.insert(getStudentEntity(2));
teacherService.insert(getTeacherEntity(2));
}
//A
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public int insert(Teacher record) throws Exception{
log.info("teacher 插入开始....");
int ss = 0;
try{
ss = teacherDAO.insert(record);
int i = 1 / 0;
}catch (Exception e){
log.error(e.getMessage());
}
return ss;
}
调用方法使用try catch 抓取异常。A方法正常抛出异常,事务进行了会滚,也就是student和teacher都进行了会滚。但是报 Transaction rolled back because it has been marked as rollback-only 异常,这个异常简单来讲,就是事务的传播机制导致的,teacher事务默认是用testDemo01调用方法的事务,但是teacher异常抛出的时候,teacher事务被标记成rollback 状态,所以,在调用方法testDemo01中即使使用trycatch捕捉了异常,同样也会做会滚,以为他俩使用的一个事务。
//调用方法
@Transactional
public void testDemo01() throws Exception{
try{
studentService.insert(getStudentEntity(3));
teacherService.insert(getTeacherEntity(3));
}catch (Exception e){
log.error(e.getMessage());
}
}
//Teacher方法
@Override
@Transactional
public int insert(Teacher record) throws Exception{
log.info("teacher 插入开始....");
int ss = teacherDAO.insert(record);
int i = 1 / 0;
return ss;
}
调整teacher的事物传播机制为 (propagation = Propagation.REQUIRES_NEW),然后teacher会回滚,Student不会进行回滚。
@Transactional
public void testDemo01() throws Exception{
try{
studentService.insert(getStudentEntity(3));
teacherService.insert(getTeacherEntity(3));
}catch (Exception e){
log.error(e.getMessage());
}
}
//
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public int insert(Teacher record) throws Exception{
log.info("teacher 插入开始....");
int ss = teacherDAO.insert(record);
int i = 1 / 0;
return ss;
}
testDemo01方法和Teacher 都使用trycatch 处理,Teacher不抛出异常,testDemo01也不抛出异常,AB不回滚
@Transactional
public void testDemo01() throws Exception{
try{
studentService.insert(getStudentEntity(4));
teacherService.insert(getTeacherEntity(3));
}catch (Exception e){
log.error(e.getMessage());
}
}
//
@Override
@Transactional
public int insert(Teacher record) throws Exception{
log.info("teacher 插入开始....");
int ss = 0;
try {
ss = teacherDAO.insert(record);
int i = 1 / 0;
} catch (Exception e) {
log.error(e.getMessage());
}
return ss;
}
testDemo01方法和Teacher 都使用trycatch 处理,Teacher修改事物隔离级别,不抛出异常,testDemo01也不抛出异常,AB不回滚
@Transactional
public void testDemo01() throws Exception{
try{
studentService.insert(getStudentEntity(5));
teacherService.insert(getTeacherEntity(4));
}catch (Exception e){
log.error(e.getMessage());
}
}
//
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public int insert(Teacher record) throws Exception{
log.info("teacher 插入开始....");
int ss = 0;
try {
ss = teacherDAO.insert(record);
int i = 1 / 0;
} catch (Exception e) {
log.error(e.getMessage());
}
return ss;
}
testDemo01方法和Teacher 都使用trycatch 处理,Teacher抛出异常,testDemo01不抛出异常,AB不回滚
@Transactional
public void testDemo01() throws Exception{
try{
studentService.insert(getStudentEntity(6));
teacherService.insert(getTeacherEntity(5));
}catch (Exception e){
log.error(e.getMessage());
}
}
// @Override
@Transactional
public int insert(Teacher record) throws Exception{
log.info("teacher 插入开始....");
int ss = 0;
try {
ss = teacherDAO.insert(record);
int i = 1 / 0;
} catch (Exception e) {
log.error(e.getMessage());
throw new Exception(e.getMessage());
}
return ss;
}
testDemo01方法和Teacher 都使用trycatch 处理,Teacher抛出异常,testDemo01抛出异常(不指定那个异常回滚,注意异常要是RuntimeException,不能是其以上的异常,不然会会滚失败,或者指定异常会滚),AB回滚
@Transactional
public void testDemo01() throws Exception{
try{
studentService.insert(getStudentEntity(8));
teacherService.insert(getTeacherEntity(7));
}catch (Exception e){
log.error(e.getMessage());
throw new RuntimeException(e.getCause());
}
}
//或者指定会滚异常
@Transactional(rollbackFor = {Exception.class})
public void testDemo01() throws Exception{
try{
studentService.insert(getStudentEntity(8));
teacherService.insert(getTeacherEntity(7));
}catch (Exception e){
log.error(e.getMessage());
throw new Exception(e.getCause());
}
}
//
@Override
@Transactional
public int insert(Teacher record) throws Exception{
log.info("teacher 插入开始....");
int ss = 0;
try {
ss = teacherDAO.insert(record);
int i = 1 / 0;
} catch (Exception e) {
log.error(e.getMessage());
throw new Exception(e.getMessage());
}
return ss;
}
如果使用循环的方式处理异常,如何保证每次循环中 testDemo01中student和teacher 同时会滚,同时有不影响下次插入呢,就是,student每新增一条数据,teacher新增三条,他们的事务在一个事务中,每次执行一次遍历 ,AB都新增数据。然而在遍历中,某一次遍历出现异常后,AB都进行会滚,同时不影响上次遍历数据,不能中断遍历。解决办法是在调用方法时,首先要设立事务的传播特性修改成REQUIRES_NEW(开启新的事务,不在归调用者的事务管理,每次遍历的时候都会开启新事务),另外使用trycatch捕获异常后使用手动操作异常时会滚(这样就不会影响下次遍历了)。异常是否抛出对于调用者不影响。
@Transactional
public void testC() throws Exception{
for (int i = 1; i <4; i++) {
try {
testService.testDemo01(i);
} catch (Exception e) {
continue;
}
}
}
//
@Transactional(propagation = Propagation.REQUIRES_NEW,rollbackFor = {Exception.class})
public void testDemo01(int i) throws Exception{
try{
studentService.insert(getStudentEntity(i));
teacherService.insert(getTeacherEntity(i));
}catch (Exception e){
log.error(e.getMessage());
//手动回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
throw new Exception(e.getCause());
}
}
//
@Override
@Transactional
public int insert(Teacher record) throws Exception{
log.info("teacher 插入开始....");
int ss = 0;
try {
int k= record.getId();
for (int i = 1; i < 3; i++) {
if (k==1){
record.setId(1+i);
}
if (k==2){
record.setId(3+i);
}
if (k==3){
record.setId(6+i);
}
ss = teacherDAO.insert(record);
if (k==2){
int t = 1 / 0;
}
}
} catch (Exception e) {
log.error(e.getMessage());
throw new Exception(e.getMessage());
}
return ss;
}