spring传播机制的讲解参考:
https://segmentfault.com/a/1190000013341344#articleHeader3
http://blog.51cto.com/jaeger/1761660
以下15种情况,大多都是网上讲解spring传播性不会讲的,以下都是新自测试过的结果,并写了几条总结。
spring事务的几种情况
需要注意的是,如果抛出的异常不是RuntimeException而是Exception,则需要通过rollbakfor指定,不然事务当中抛出的Exception异常是不回滚的。
1.同类中,事务方法a调用非事务方法b。在b的最后抛异常,a捕获b的异常。结果是:都不回滚。
2.同类中,事务方法a调用非事务方法b。在b的最后抛异常,a不捕获b的异常。结果是:都回滚。
3.同类中,事务方法a调用非事务方法b。在a的最后抛出异常。结果是:都回滚。
4.同类中,事务方法a调用配置过事务的方法b。在b的最后抛出异常,a捕获b的异常。结果是:都不回滚。
5.同类中,事务方法a调用配置过事务的方法b。在b的最后抛出异常,a不捕获b的异常。结果是:都回滚。
6.同类中,事务方法a调用配置过事务的方法b。在a的最后抛出异常,结果是:都回滚。
7.同类中,非事务方法a调用配置过事务的方法b,在b最后抛出异常,a捕获b的异常。结果是:都不回滚。
8.同类中,非事务方法a调用配置过事务的方法b,在b最后抛出异常,a不捕获b的异常。结果是:都不回滚。
9.同类中,非事务方法a调用配置过事务的方法b,在a最后抛出异常。结果是:都不回滚。
10.非同类中,事务方法a调用非事务方法b,在b的最后抛出异常,a捕获导常。结果是:都不回滚。
11.非同类中,事务方法a调用非事务方法b,在b的最后抛出异常,a不捕获异常。结果是:都回滚。
12.非同类中,事务方法a调用非事务方法b,在a的最后抛出异常。结果是:都回滚。
13.非同类中,事务方法a调用嵌套事务方法b,在b的最后抛出异常,a捕获b的异常。结果是:只有b回滚。
14.非同类中,事务方法a调用嵌套事务方法b,在b的最后抛出异常,a不捕获b的异常。结果是:都回滚。
15.非同类中,事务方法a调用嵌套事务方法b,在a的最后抛出异常。结果是:都回滚。
16.非同类中,非事务方法a调用事务方法b,在b的最后抛出异常,a捕获b的异常。结果是:只有b回滚。
17.非同类中,非事务方法a调用事务方法b,在b的最后抛出异常,a不捕获b的异常。结果是:只有b回滚。
18.非同类中,非事务方法a调用事务方法b,在a的最后抛出异常。结果是:都不回滚。
19.非同类中,非事务方法a调用嵌套事务方法b,在b的最后抛出异常,a捕获b的异常。结果是:只有b回滚。
20.非同类中,非事务方法a调用嵌套事务方法b,在b的最后抛出异常,a不捕获b的异常。结果是:只有b回滚。
21.非同类中,非事务方法a调用嵌套事务方法b,在a的最后抛出异常。结果是:都不回滚。
22.非同类中,事务方法a多级嵌套调用非事务方法,在任一级非事务方法中抛出异常,a捕获异常,结果是都不回滚。
23.非同类中,事务方法a多级嵌套调用非事务方法,在任一级非事务方法中抛出异常,a不捕获异常。结果是都回滚。
24.非同类中,事务方法a多级嵌套调用非事务方法,在a的最后抛出异常。结果是都回滚。
以下是对第18条的一个举例:
A类中,a为非事务方法
public void a() throws Exception {
Task t = new Task();
t.setOrderContent("非事务方法测试A");
dao.insert(t);
new B().b();
throw new Exception();
}
B类中,b为事务方法
public void b() {
Task t = new Task();
t.setOrderContent("事务方法测试B");
dao.insert(t);
}
以下是对第13条的一个举例:非同类中,事务方法a调用嵌套事务方法b,在b的最后抛出异常,a捕获b的异常。结果是:只有b回滚。
A类中,a为事务方法
public void a() {
try{
Task t = new Task();
t.setOrderContent("非事务方法测试A");
// 由于异常被捕获了,所以下面的插入不会回滚,因为异常被捕获后,方法a感知不到了
dao.insert(t);
new B().b();
}catch(Exception e){
e.printStack();
}
}
B类中,b为嵌套事务方法
public void b() throws Exception {
Task t = new Task();
t.setOrderContent("事务方法测试B");
dao.insert(t);
throw new Exception();
}
总结:
spring的事务传播属性不适用于同类中的方法调用,即事务方法在被同类中的方法调用时会被当作非事务方法。
事务方法调用非事务方法(包括本类中事务不生效的方法)时,事务方法捕获了被调用方法里的异常时就都不会回滚,不捕获就都回滚。
非事务方法调用非事务方法(包括本类中事务不生效的方法)和调用嵌套事务时一样都不会互不影响,即都会自动提交。
事务方法多级嵌套调用非事务方法,和调用一级非事务方法结果是一致的,即只要事务方法捕获了异常就都不回滚,不捕获就都回滚。
一个方法b加入到事务方法a中时,不论b抛出的异常是否被a捕获,结果是整个事务都会回滚。因为始终是一个事务。
事务方法a调用一个新开的事务方法b,在b的最后抛出异常,a捕获异常。结果是只有b回滚。因为都不在同一个事务当中了。
事务在spring中的几个重点:
事务的隔离级别是数据库本身的事务功能,然而事务的传播属性则是Spring自己为我们提供的功能,数据库事务没有事务的传播属性这一说法。
事务的前提是要数据库支持事务
事务传播机制只适用于不同bean之间的方法调用
只要一个方法开启了事务,那么就从此时设置了一个事务点。
一个线程的事务不会影响到另外一个线程的事务。例如,插入日志的方法是需要始终保持成功的,而不希望因为事务内的某些方法导致的回滚而回滚,所以一般的都会新开线程来执行插入日志的方法。
一个线程在没有结束当前事务的时候,是无法释放资源来执行其它事务的。
事务在数据库中的几个重点:
数据库执行事务的时候,是先将数据插入到日志中,如果没有遇到回滚,则在提交事务的时候将日志操作同步到数据库。如果回滚的话,则日志的操作不再插入数据库中。
如果发生回滚,则主键还是会增大的即主键会变得不连续。例如,本应该插入的数据id为100,但是发生了回滚,则后面再正确插入的数据的主键会是101。
JDBC对事务的支持是放在Connection连接中的。
补充
如果使用的@Transactionl注解,最好不要加在接口上。
在接口上使用 @Transactional 注解,只能当你设置了基于接口的代理时它才生效。因为注解是 不能继承 的,这就意味着如果正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装。