实战Spring中的八大事务

实战Spring中的八大事务,第1张

实战Spring中的八大事务 一、测试前的准备

数据表结构:

1. StuService
package com.ybqdren.service;

import com.ybqdren.pojo.Stu;


public interface StuService {
    public Stu getStuInfo(int id);

    public void saveStu();

    public void saveStu(int id);

    public void updateStu(int id);

    public void deleteStu(int id);

    public void saveParent();

    public void saveChildren();

}


2. StuServiceImpl
package com.ybqdren.service.impl;

import com.ybqdren.mapper.StuMapper;
import com.ybqdren.pojo.Stu;
import com.ybqdren.service.StuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;




@Service
public class StuServiceImpl implements StuService {
    @Autowired
    private StuMapper stuMapper;

    //@Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public Stu getStuInfo(int id) {
        return (Stu) stuMapper.selectByPrimaryKey(id);
    }

    //@Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void saveStu() {
        Stu stu = new Stu();
        stu.setName("jack");
        stu.setAge(18);
        stuMapper.insert(stu);

    }

   // @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void saveStu(int id) {

    }

    //@Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void updateStu(int id) {
        Stu stu = new Stu();
        stu.setId(id);
        stu.setName("lucy");
        stu.setAge(20);
        stuMapper.updateByPrimaryKey(stu);
    }

    //@Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void deleteStu(int id) {
        stuMapper.deleteByPrimaryKey(id);
    }

    @Override
    public void saveParent() {
        Stu stu = new Stu();
        stu.setName("parent");
        stu.setAge(19);
        stuMapper.insert(stu);
    }

    @Override
    public void saveChildren() {
        saveChild1();
    }

    public void saveChild1(){
        Stu stu1 = new Stu();
        stu1.setName("child-1");
        stu1.setAge(11);
        stuMapper.insert(stu1);
    }

    public void saveChild2(){
        Stu stu1 = new Stu();
        stu1.setName("child-2");
        stu1.setAge(11);
        stuMapper.insert(stu1);
    }
}


3. TestTransService
package com.ybqdren.service;

public interface TestTransService {
    public void testPropagationTrans();
}


4. TestTransServiceImpl
package com.ybqdren.service.impl;

import com.ybqdren.service.StuService;
import com.ybqdren.service.TestTransService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class TestTransServiceImpl implements TestTransService {

    @Autowired
    private StuService stuService;

    // @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void testPropagationTrans() {
        stuService.saveParent();
    }
}


5. TransTest
import com.ybqdren.Application;
import com.ybqdren.service.StuService;
import com.ybqdren.service.TestTransService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;



@SpringBootTest(classes = Application.class)
public class TransTest {
    @Autowired
    private StuService stuService;

    @Autowired
    private TestTransService testTransService;

    @Test
    public void myTest() {
        testTransService.testPropagationTrans();
    }
}


二、不使用事务 1. StuServiceImpl
package com.ybqdren.service.impl;

import com.ybqdren.mapper.StuMapper;
import com.ybqdren.pojo.Stu;
import com.ybqdren.service.StuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;




@Service
public class StuServiceImpl implements StuService {
    @Autowired
    private StuMapper stuMapper;

 // .....
    
    @Override
    public void saveParent() {
        Stu stu = new Stu();
        stu.setName("parent");
        stu.setAge(19);
        stuMapper.insert(stu);
    }

    @Override
    public void saveChildren() {
        saveChild1();
        // 在两次添加数据的 *** 作之间加入一个绝对会报异常的代码
        int a = 1/0;
        saveChild2();
    }

    public void saveChild1(){
        Stu stu1 = new Stu();
        stu1.setName("child-1");
        stu1.setAge(11);
        stuMapper.insert(stu1);
    }

    public void saveChild2(){
        Stu stu1 = new Stu();
        stu1.setName("child-2");
        stu1.setAge(11);
        stuMapper.insert(stu1);
    }
}


2. TestTransServiceImpl
package com.ybqdren.service.impl;

import com.ybqdren.service.StuService;
import com.ybqdren.service.TestTransService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class TestTransServiceImpl implements TestTransService {

    @Autowired
    private StuService stuService;

    // @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void testPropagationTrans() {
        stuService.saveParent();

        // 新增
        stuService.saveChildren();
    }
}


3. *** 作执行后的数据库 1) 报异常




2)数据库(前后)


可以看到saveChildren只保存了一数据,child-2并没有插入进去

在发生异常后,child-2是无法保存到数据库的,也没有进行回滚​


三、事务 1. REQUIRED 1)简介
  1. 使用当前的事务,如果当前没有事务,则自己新建一个事务,子方法是必须运行在一个事务中的;
  2. 如果当前存在事务,则加入这个事务,成为一个整体。

2)在父方法中添加 在TestTransServiceImpl中开启事务
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void testPropagationTrans() {
        stuService.saveParent();

        stuService.saveChildren();
    }

执行后

可以看到,此处数据库中并没有插入数据
因为在此处进行了事务传播REQUIRED,虽然saveParent和saveChild方法都没有事务,但是它们也传播到了REQUIRED事务
所以当父方法使用REQUIRED事务时,子方法发生异常后,两个子方法中的事务都会进行回滚


3)在单个子方法中添加 清除父方法上的事务
//    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void testPropagationTrans() {
        stuService.saveParent();

        stuService.saveChildren();
    }

在saveChild方法上添加一个事务
    @Override
    public void saveParent() {
        Stu stu = new Stu();
        stu.setName("parent");
        stu.setAge(19);
        stuMapper.insert(stu);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void saveChildren() {
        saveChild1();
        int a = 1/0;
        saveChild2();
    }


public void saveChild1(){
    Stu stu1 = new Stu();
    stu1.setName("child-1");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

public void saveChild2(){
    Stu stu1 = new Stu();
    stu1.setName("child-2");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

执行后


可以看到saveParent方法执行的数据添加到了数据库,而saveChild没有。
也就是说,当前的整个方法方法体中不带有事务时,他回去重新创建一个事务


也就是说saveChildren方法必须要存在于某个事务中去运行,所以它发生异常后进行了回滚,而saveParent没有事务。


2. SUPPORTS 1)简介

如果当前有事务,则使用事务;如果当前没有事务,则不使用事务。

2)外层没有事务,而子方法有
@Override
public void testPropagationTrans() {
    stuService.saveParent();

    stuService.saveChildren();
}

@Override
public void saveParent() {
    Stu stu = new Stu();
    stu.setName("parent");
    stu.setAge(19);
    stuMapper.insert(stu);
}

@Transactional(propagation = Propagation.SUPPORTS)
@Override
public void saveChildren() {
    saveChild1();
    int a = 1/0;
    saveChild2();
}

public void saveChild1(){
    Stu stu1 = new Stu();
    stu1.setName("child-1");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

public void saveChild2(){
    Stu stu1 = new Stu();
    stu1.setName("child-2");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

执行后





3)外层使用事务,而内层其中一个子方法也是用事务
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void testPropagationTrans() {
    stuService.saveParent();

    stuService.saveChildren();
}

@Override
public void saveParent() {
    Stu stu = new Stu();
    stu.setName("parent");
    stu.setAge(19);
    stuMapper.insert(stu);
}

@Transactional(propagation = Propagation.SUPPORTS)
@Override
public void saveChildren() {
    saveChild1();
    int a = 1/0;
    saveChild2();
}


public void saveChild1(){
    Stu stu1 = new Stu();
    stu1.setName("child-1");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

public void saveChild2(){
    Stu stu1 = new Stu();
    stu1.setName("child-2");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

执行后



前后都为空


3. MANDATORY 1)简介

该传播属性强制必须存在一个事务,如果不存在,则抛出异常。

2)外层无事务,其中一个子方法有事务,而另一个方法没有事务
    @Override
    public void testPropagationTrans() {
        stuService.saveParent();

        stuService.saveChildren();
    }
@Override
public void saveParent() {
    Stu stu = new Stu();
    stu.setName("parent");
    stu.setAge(19);
    stuMapper.insert(stu);
}

@Transactional(propagation = Propagation.MANDATORY)
@Override
public void saveChildren() {
    saveChild1();
    int a = 1/0;
    saveChild2();
}

public void saveChild1(){
    Stu stu1 = new Stu();
    stu1.setName("child-1");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

public void saveChild2(){
    Stu stu1 = new Stu();
    stu1.setName("child-2");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

执行后 控制台报错




数据库






3)外层有事务,子方法一个方法有事务,另一个没有
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void testPropagationTrans() {
        stuService.saveParent();

        stuService.saveChildren();
    }

@Override
public void saveParent() {
    Stu stu = new Stu();
    stu.setName("parent");
    stu.setAge(19);
    stuMapper.insert(stu);
}

@Transactional(propagation = Propagation.MANDATORY)
@Override
public void saveChildren() {
    saveChild1();
    int a = 1/0;
    saveChild2();
}

public void saveChild1(){
    Stu stu1 = new Stu();
    stu1.setName("child-1");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

public void saveChild2(){
    Stu stu1 = new Stu();
    stu1.setName("child-2");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

执行后




数据库






4. REQUIRES_NEW 1)简介
  1. 如果当前有事务,则挂起该事务,并且自己创建一个新的事务给自己使用;
  2. 如果当前没有事务,则同 REQUIRED。

2)外层无事务,子方法有事务,而父方法没有事务
    @Override
    public void testPropagationTrans() {
        stuService.saveParent();

        stuService.saveChildren();
    }
@Override
public void saveParent() {
    Stu stu = new Stu();
    stu.setName("parent");
    stu.setAge(19);
    stuMapper.insert(stu);
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void saveChildren() {
    saveChild1();
    int a = 1/0;
    saveChild2();
}

public void saveChild1(){
    Stu stu1 = new Stu();
    stu1.setName("child-1");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

public void saveChild2(){
    Stu stu1 = new Stu();
    stu1.setName("child-2");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

执行后




数据库






分析
    @Override
    public void testPropagationTrans() {
        stuService.saveParent();

        stuService.saveChildren();
    }

saveParent没有事务,而saveChildren有事务,所以会将后者和前者 *** 作区分开来,后者发生错误会进行回滚,但是前者会正常存储到数据库中。


3)外层有事务,子方法有事务,父方法没有事务
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void testPropagationTrans() {
        stuService.saveParent();

        stuService.saveChildren();
    }
@Override
public void saveParent() {
    Stu stu = new Stu();
    stu.setName("parent");
    stu.setAge(19);
    stuMapper.insert(stu);
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void saveChildren() {
    saveChild1();
    int a = 1/0;
    saveChild2();
}

public void saveChild1(){
    Stu stu1 = new Stu();
    stu1.setName("child-1");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

public void saveChild2(){
    Stu stu1 = new Stu();
    stu1.setName("child-2");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

执行后




数据库



前后都为空。


分析
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void saveChildren() {
    saveChild1();
    int a = 1/0;
    saveChild2();
}

saveChildren方法执行后会产生1个byzero的异常,而这个异常会传递给其调用方法:

@Transactional(propagation = Propagation.REQUIRED)
@Override
public void testPropagationTrans() {
    stuService.saveParent();

    stuService.saveChildren();
}

因为当前方法有事务REQUIRED,变成了一个整体,所以就会影响当前方法中一起被调用的saveParent,所以也导致saveParent也出现了回滚。


4)外层使用事务也产生异常,子方法有事务,父方法没有事务
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void testPropagationTrans() {
    stuService.saveParent();

    stuService.saveChildren();
    
    int a = 1/0;
}
@Override
public void saveParent() {
    Stu stu = new Stu();
    stu.setName("parent");
    stu.setAge(19);
    stuMapper.insert(stu);
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void saveChildren() {
    saveChild1();
    saveChild2();
}

public void saveChild1(){
    Stu stu1 = new Stu();
    stu1.setName("child-1");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

public void saveChild2(){
    Stu stu1 = new Stu();
    stu1.setName("child-2");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

执行后




数据库



多了两条数据:



分析

因为子方法saveChildren中使用了新的事务,所以当前事务是被挂起的,所以当前方法的事务是不会影响到其子方法的:

@Transactional(propagation = Propagation.REQUIRED)
@Override
public void testPropagationTrans() {
    stuService.saveParent();

    stuService.saveChildren();

    int a = 1/0;
}

但是saveParent中没有使用事务,所以会被回滚,所以数据库中会保存saveChildren中插入的值:



5)外层有REQUIRED事务,子方法有REQUIRED事务,父方法没有事务

子方法和外层都是用REQUIRED事务,也就是两个方法都使用同一个事务:

@Transactional(propagation = Propagation.REQUIRED)
@Override
public void testPropagationTrans() {
    stuService.saveParent();

    stuService.saveChildren();

    int a = 1/0;
}
@Override
public void saveParent() {
    Stu stu = new Stu();
    stu.setName("parent");
    stu.setAge(19);
    stuMapper.insert(stu);
}

@Transactional(propagation = Propagation.REQUIRED)
@Override
public void saveChildren() {
    saveChild1();
    //        int a = 1/0;
    saveChild2();
}

public void saveChild1(){
    Stu stu1 = new Stu();
    stu1.setName("child-1");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

public void saveChild2(){
    Stu stu1 = new Stu();
    stu1.setName("child-2");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

执行后

没有插入值:



分析

两个方法都共用了同一个事务,所以不管在哪个方法中抛出异常,都会进行回滚。


5. NOT_SUPPORTED 1)简介

如果当前有事务,则把事务挂起,自己不使用事务去运行数据库 *** 作。

2)外层无事务,子方法不使用事务,父方法没有事务
@Override
public void testPropagationTrans() {
    stuService.saveParent();

    stuService.saveChildren();

}
@Override
public void saveParent() {
    Stu stu = new Stu();
    stu.setName("parent");
    stu.setAge(19);
    stuMapper.insert(stu);
}

@Transactional(propagation = Propagation.NOT_SUPPORTED)
@Override
public void saveChildren() {
    saveChild1();
    int a = 1/0;
    saveChild2();
}

public void saveChild1(){
    Stu stu1 = new Stu();
    stu1.setName("child-1");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

public void saveChild2(){
    Stu stu1 = new Stu();
    stu1.setName("child-2");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

执行后




数据库



虽然控制台有报异常,但是并没有进行回滚:



分析

外层没有事务,且子方法中也不使用事务,因此产生了异常也没有进行回滚。


3)外层有事务,子方法不使用事务,父方法没有事务
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void testPropagationTrans() {
    stuService.saveParent();

    stuService.saveChildren();
}

@Override
public void saveParent() {
    Stu stu = new Stu();
    stu.setName("parent");
    stu.setAge(19);
    stuMapper.insert(stu);
}

@Transactional(propagation = Propagation.NOT_SUPPORTED)
@Override
public void saveChildren() {
    saveChild1();
    int a = 1/0;
    saveChild2();
}

public void saveChild1(){
    Stu stu1 = new Stu();
    stu1.setName("child-1");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

public void saveChild2(){
    Stu stu1 = new Stu();
    stu1.setName("child-2");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

执行后




数据库






分析

saveChildren方法中抛出了一个异常,所以只执行到了saveChild1():

@Transactional(propagation = Propagation.NOT_SUPPORTED)
@Override
public void saveChildren() {
    saveChild1();
    int a = 1/0;
    saveChild2();
}

而因为当前方法是不使用异常的,所以saveChild1是没有发生回滚的。
而调用方是本身有事务的:

@Transactional(propagation = Propagation.REQUIRED)
@Override
public void testPropagationTrans() {
    stuService.saveParent();

    stuService.saveChildren();

}

所以从saveChildren中产生的异常,也会让此处同时被调用的saveParent方法被回滚。


6. NEVER 1)简介

如果当前有事务存在,则抛出异常。

2)外层有事务REQUIRED,而子方法有NEVER事务
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void testPropagationTrans() {
    stuService.saveParent();

    stuService.saveChildren();

}

@Override
public void saveParent() {
    Stu stu = new Stu();
    stu.setName("parent");
    stu.setAge(19);
    stuMapper.insert(stu);
}

@Transactional(propagation = Propagation.NEVER)
@Override
public void saveChildren() {
    saveChild1();
    int a = 1/0;
    saveChild2();
}

public void saveChild1(){
    Stu stu1 = new Stu();
    stu1.setName("child-1");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

public void saveChild2(){
    Stu stu1 = new Stu();
    stu1.setName("child-2");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

执行后

提示已经有事务存在的异常:



数据库

没有任何数据插入:



3)外层没有事务,子方法有NEVER事务
    @Override
    public void testPropagationTrans() {
        stuService.saveParent();

        stuService.saveChildren();

    }
@Override
public void saveParent() {
    Stu stu = new Stu();
    stu.setName("parent");
    stu.setAge(19);
    stuMapper.insert(stu);
}

@Transactional(propagation = Propagation.NEVER)
@Override
public void saveChildren() {
    saveChild1();
    int a = 1/0;
    saveChild2();
}

public void saveChild1(){
    Stu stu1 = new Stu();
    stu1.setName("child-1");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

public void saveChild2(){
    Stu stu1 = new Stu();
    stu1.setName("child-2");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}


执行后




数据库






分析

没有事务,就没有相应的回滚。


7. NESTED 1)简介
  1. 如果当前有事务,则开启子事务(嵌套事务),嵌套事务是独立提交或者回滚;如果当前没有事务,则同 REQUIRED。
  2. 但是如果主事务提交,则会携带子事务一起提交。
  3. 如果主事务回滚,则子事务会一起回滚。相反,子事务异常,则父事务可以回滚或不回滚。

2)外层使用REQUIRED事务有异常,子方法使用NESTED事务无异常
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void testPropagationTrans() {
    stuService.saveParent();

    stuService.saveChildren();

    int a = 1/0;
}
@Override
public void saveParent() {
    Stu stu = new Stu();
    stu.setName("parent");
    stu.setAge(19);
    stuMapper.insert(stu);
}

@Transactional(propagation = Propagation.NESTED)
@Override
public void saveChildren() {
    saveChild1();
    saveChild2();
}

public void saveChild1(){
    Stu stu1 = new Stu();
    stu1.setName("child-1");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

public void saveChild2(){
    Stu stu1 = new Stu();
    stu1.setName("child-2");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

执行后




数据库

什么都没有:



分析

有父子嵌套事务存在话,在调用方法中发生的异常,那么在嵌套事务里面的事务也会被回滚。


3)外层使用REQUIRED事务无异常,子方法使用NESTED事务有异常
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void testPropagationTrans() {
    stuService.saveParent();

    try{
        // save point 保存点: 对当前事务的异常进行catch之后,就不会影响同层次调用的其他方法 其他 *** 作
        stuService.saveChildren();
    }catch (Exception e){
        e.printStackTrace();
    }

}
@Override
public void saveParent() {
    Stu stu = new Stu();
    stu.setName("parent");
    stu.setAge(19);
    stuMapper.insert(stu);
}

@Transactional(propagation = Propagation.NESTED)
@Override
public void saveChildren() {
    saveChild1();
    int a = 1/0;
    saveChild2();
}

public void saveChild1(){
    Stu stu1 = new Stu();
    stu1.setName("child-1");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

public void saveChild2(){
    Stu stu1 = new Stu();
    stu1.setName("child-2");
    stu1.setAge(11);
    stuMapper.insert(stu1);
}

执行后




数据库




分析

使用save point 将saveChildren方法中的异常隔离开,不会影响到当前调用方中其他的方法。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5611752.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-15
下一篇 2022-12-15

发表评论

登录后才能评论

评论列表(0条)

保存