首先MySQL建立测试表,只是测试用所以比较简单
test_isolation
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| num | int(11) | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
test_propagation
+-------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| num | int(11) | YES | | NULL | |
+-------+---------+------+-----+---------+-------+
项目采用maven+maven创建,junit单元测试运行测试
概念
本地事务
数据库事务,默认事务为自动提交,因此如果一个业务逻辑类中有多次数据库操作将无法保证事务的一致性。
Spring事务
对本地事务操作的一次封装,相当于把使用JDBC代码开启、提交、回滚事务进行了封装。
上述两个概念会在demo中用到,以方便大家理解代码。
事务传播性:
1、PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,该设置是最常用的设置。
2、PROPAGATION_SUPPORTS:自身不会开启事务,在事务范围内则使用相同事务,否则不使用事务。‘
3、PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
4、PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。
5、PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
6、PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
7、PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
Junit单元测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:applicationContext.xml"})
public class TestPropagation {
@Autowired
private ITestIsolationService isolationService;
@Autowired
private ITestPropagationService propagationService;
@Test
public void testPropagation() {
isolationService.add("insert test_isolation values(1,1)");
}
}
业务层代码都是使用spring的JdbcTemplate操作
PROPAGATION_REQUIRED
// TestIsolationServiceImpl
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void add(String sql) {
jdbcTemplate.execute(sql);
propagationService.add("insert test_propagation values(1,1)");
throw new RuntimeException();
}
// TestPropagationServiceImpl
@Transactional(propagation = Propagation.REQUIRED)
@Override
public void add(String sql) {
jdbcTemplate.execute(sql);
}
经测试无论在isolationservice还是propagationservice如果不抛出异常,那么数据提交成功,如果抛出异常,数据提交失败。这说明isolationservice和propagationservice使用的是同一个事务,并且只要方法被调用就开启事务。
PROPAGATION_REQUIRES_NEW
// TestIsolationServiceImpl
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void add(String sql) {
jdbcTemplate.execute(sql);
propagationService.add("insert test_propagation values(1,1)");
throw new RuntimeException();
}
// TestPropagationServiceImpl
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void add(String sql) {
jdbcTemplate.execute(sql);
}
经测试如果在isolationservice中抛出异常,isolationservice数据不能正确提交,propagationservice被正确提交。说明isolationservice和propagationservice是在两个独立的事务中运行,并且只要方法被调用就开启事务。
PROPAGATION_SUPPORTS
// TestIsolationServiceImpl
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public void add(String sql) {
jdbcTemplate.execute(sql);
propagationService.add("insert test_propagation values(1,1)");
throw new RuntimeException();
}
// TestPropagationServiceImpl
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public void add(String sql) {
jdbcTemplate.execute(sql);
}
经测试如果在isolationservice中抛出异常,isolationservice和propagationservice都被正确提交。说明isolationservice和propagationservice没有被spring管理和开启事务,而是使用了本地事务,由于本地事务默认自动提交因此数据都提交成功,但它们使用的却不是同一个事务,一旦出现异常将导致数据的不一致。
PROPAGATION_NOT_SUPPORTED
// TestIsolationServiceImpl
@Transactional(propagation = Propagation.NOT_SUPPORTED)
@Override
public void add(String sql) {
jdbcTemplate.execute(sql);
throw new RuntimeException();
}
经测试如果在isolationservice中抛出异常,isolationservice正确提交。说明isolationservice没有被spring管理和开启事务,而是使用了本地事务,由于本地事务默认自动提交因此数据都提交成功。
其他几种大家可以自行测试,demo代码已经上传至git,其中demo中还有zookeeper,dubbo,rabbitmq,webservice,aop,等等一系列的测试用力,大家可以参考
代码地址:https://git.coding.net/scott-huo/product.git,git@git.coding.net:scott-huo/product.git
有问题可以加群询问,共同探讨学习