在准备好前期的项目搭建后,接下来就一个个的测试,首先测试事务传播的Required
Service层两个实现类
Service层两个实现类,只是更换了方法事务传播的属性,其他都一样,后续测试也只修改传播的属性即可,这里只列一次便于理解。
package Service; import javax.annotation.Resource; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import DAO.EmpDAO;
import Entity.EMP; @Service("service1")
public class EMPService1Impl implements EMPService1{ @Resource(name="empDAO")
EmpDAO dao; @Transactional(propagation=Propagation.REQUIRED)
public void addEmp1(EMP emp) {
dao.addEMP1(emp);
} }
package Service; import javax.annotation.Resource; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import DAO.EmpDAO;
import Entity.EMP; @Service("service2")
public class EMPService2Impl implements EMPService2{ @Resource(name="empDAO")
EmpDAO dao; @Transactional(propagation=Propagation.REQUIRED)
public void addEmp2(EMP emp) {
dao.addEMP2(emp);
} @Transactional(propagation=Propagation.REQUIRED)
public void addEmp2WithException(EMP emp) {
dao.addEMP2(emp);
throw new RuntimeException();
} }
LayerT层代码
package LayerT; import javax.annotation.Resource; import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import Entity.EMP;
import Service.EMPService1;
import Service.EMPService2; /**
* 测试Required
* @author yangchaolin
*
*/
@Component("requiredTest")
public class RequiredTest {
@Resource(name="service1")
EMPService1 service1;
@Resource(name="service2")
EMPService2 service2; /**
* 外层方法没有事务,但是抛出异常
* @param emp1
* @param emp2
*/
public void testRequiredWithoutTransaction1(EMP emp1,EMP emp2) {
service1.addEmp1(emp1);
service2.addEmp2(emp2);
throw new RuntimeException();
}
/**
* 外层方法没有事务,内层有方法抛出异常
* @param emp1
* @param emp2
*/
public void testRequiredWithoutTransaction2(EMP emp1,EMP emp2) {
service1.addEmp1(emp1);
service2.addEmp2WithException(emp2);
}
/**
* 外层方法有事务,但是抛出异常
* @param emp1
* @param emp2
*/
@Transactional(propagation=Propagation.REQUIRED)
public void testRequiredWithTransaction1(EMP emp1,EMP emp2) {
service1.addEmp1(emp1);
service2.addEmp2(emp2);
throw new RuntimeException();
}
/**
* 外层方法有事务,内层有方法抛出异常
* @param emp1
* @param emp2
*/
@Transactional(propagation=Propagation.REQUIRED)
public void testRequiredWithTransaction2(EMP emp1,EMP emp2) {
service1.addEmp1(emp1);
service2.addEmp2WithException(emp2);
}
/**
* 外层方法有事务,内存方法抛出的异常被捕获
* @param emp1
* @param emp2
*/
@Transactional(propagation=Propagation.REQUIRED)
public void testRequiredWithTransaction3(EMP emp1,EMP emp2) {
service1.addEmp1(emp1);
try {
service2.addEmp2WithException(emp2);
}catch(Exception e) {
System.out.println("回滚");
}
} }
测试代码
其中baseTest为父类,里面读取Spring-MVC.xml和Spring-Mybatis配置文件后初始化了ApplicationContext,继承它后后续其他事务传播属性的测试就不需要重复写这一部分代码。
package TestCase; import org.junit.Test; import Entity.EMP;
import LayerT.RequiredTest; public class requiredTestCase extends baseTest{
@Test
public void test1() {
RequiredTest T1=ac.getBean("requiredTest",RequiredTest.class);
EMP emp1=new EMP("张三",18);
EMP emp2=new EMP("李四",28);
T1.testRequiredWithoutTransaction1(emp1, emp2);
}
@Test
public void test2() {
RequiredTest T1=ac.getBean("requiredTest",RequiredTest.class);
EMP emp1=new EMP("张三",18);
EMP emp2=new EMP("李四",28);
T1.testRequiredWithoutTransaction2(emp1, emp2);
}
@Test
public void test3() {
RequiredTest T1=ac.getBean("requiredTest",RequiredTest.class);
EMP emp1=new EMP("张三",18);
EMP emp2=new EMP("李四",28);
T1.testRequiredWithTransaction1(emp1, emp2);
}
@Test
public void test4() {
RequiredTest T1=ac.getBean("requiredTest",RequiredTest.class);
EMP emp1=new EMP("张三",18);
EMP emp2=new EMP("李四",28);
T1.testRequiredWithTransaction2(emp1, emp2);
}
@Test
public void test5() {
RequiredTest T1=ac.getBean("requiredTest",RequiredTest.class);
EMP emp1=new EMP("张三",18);
EMP emp2=new EMP("李四",28);
T1.testRequiredWithTransaction3(emp1, emp2);
}
}
(1)外层方法没有事务测试结果
test1 | 张三插入,李四插入 |
test2 | 张三插入,李四未插入 |
结论:在外层方法没有开启事务的情况下,传播属性为Required的方法,会各自执行事务,互不干扰,当方法出现异常时,会出现回滚,如李四就未插入。
(2)外层方法有事务测试结果
test3 | 张三未插入,李四未插入 |
test4 | 张三未插入,李四未插入 |
test5 | 张三未插入,李四未插入 |
结论:在外层方法开启事务,并且传播属性为默认Required的时候,内层方法与外层方法事务传播属性一样,会将事务绑定在一起,不论是外层还是内层方法出现异常,都会导致数据回滚,即使将内层抛出异常的方法捕获也没有用。