一、什么是事务的流传?

简略的了解就是多个事务办法互相调用时,事务如何在这些办法间流传。

二、Spring事务流传类型Propagation介绍

在Spring中对于事务的流传行为定义了七种类型别离是:REQUIRED、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER、NESTED
现有两个办法A和B,办法A执行会在数据库ATable插入一条数据,办法B执行会在数据库BTable插入一条数据,伪代码如下:

//将传入参数a存入ATable pubilc void A(a){    insertIntoATable(a);    }//将传入参数b存入BTable public void B(b){    insertIntoBTable(b);}

无事务

public void testMain(){    A(a1);  //调用A入参a1    testB();    //调用testB}public void testB(){    B(b1);  //调用B入参b1    throw Exception;     //产生异样抛出    B(b2);  //调用B入参b2}

a1数据胜利存入ATable表,b1数据胜利存入BTable表,而在抛出异样后b2数据存储就不会执行,也就是b2数据不会存入数据库,这就是没有事务的场景。

REQUIRED(Spring默认的事务流传类型)

如果以后没有事务,则本人新建一个事务,如果以后存在事务,则退出这个事务

@Transactional(propagation = Propagation.REQUIRED)public void testMain(){    A(a1);  //调用A入参a1    testB();    //调用testB}@Transactional(propagation = Propagation.REQUIRED)public void testB(){    B(b1);  //调用B入参b1    throw Exception;     //产生异样抛出    B(b2);  //调用B入参b2}

后果:
数据库没有插入新的数据,数据库还是放弃着执行testMain办法之前的状态,没有产生扭转。testMain上申明了事务,在执行testB办法时就退出了testMain的事务(以后存在事务,则退出这个事务),在执行testB办法抛出异样后事务会产生回滚,又testMain和testB应用的同一个事务,所以事务回滚后testMain和testB中的操作都会回滚,也就使得数据库依然放弃初始状态

public void testMain(){    A(a1);  //调用A入参a1    testB();    //调用testB}@Transactional(propagation = Propagation.REQUIRED)public void testB(){    B(b1);  //调用B入参b1    throw Exception;     //产生异样抛出    B(b2);  //调用B入参b2}

后果:
数据a1存储胜利,数据b1和b2没有存储。因为testMain没有申明事务,testB有申明事务且流传行为是REQUIRED,所以在执行testB时会本人新建一个事务(如果以后没有事务,则本人新建一个事务),testB抛出异样则只有testB中的操作产生了回滚,也就是b1的存储会产生回滚,但a1数据不会回滚,所以最终a1数据存储胜利,b1和b2数据没有存储

SUPPORTS

以后存在事务,则退出以后事务,如果以后没有事务,就以非事务办法执行

public void testMain(){    A(a1);  //调用A入参a1    testB();    //调用testB}@Transactional(propagation = Propagation.SUPPORTS)public void testB(){    B(b1);  //调用B入参b1    throw Exception;     //产生异样抛出    B(b2);  //调用B入参b2}

后果:
a1,b1存入数据库,b2没有存入数据库。因为testMain没有申明事务,且testB的事务流传行为是SUPPORTS,所以执行testB时就是没有事务的(如果以后没有事务,就以非事务办法执行),则在testB抛出异样时也不会产生回滚,所以最终后果就是a1和b1存储胜利,b2没有存储。

MANDATORY

以后存在事务,则退出以后事务,如果以后事务不存在,则抛出异样。

public void testMain(){    A(a1);  //调用A入参a1    testB();    //调用testB}@Transactional(propagation = Propagation.MANDATORY)public void testB(){    B(b1);  //调用B入参b1    throw Exception;     //产生异样抛出    B(b2);  //调用B入参b2}

后果:
a1存储胜利,而b1和b2没有存储。b1和b2没有存储,并不是事务回滚的起因,而是因为testMain办法没有申明事务,在去执行testB办法时就间接抛出事务要求的异样(如果以后事务不存在,则抛出异样),所以testB办法里的内容就没有执行。

REQUIRES_NEW

创立一个新事务,如果存在以后事务,则挂起该事务,即在执行时,不管以后是否存在事务,总是会新建一个事务,所谓挂起就是以后事务要等到新事务执行完能力继续执行,两个事务是独立的。

@Transactional(propagation = Propagation.REQUIRED)public void testMain(){    A(a1);  //调用A入参a1    testB();    //调用testB    throw Exception;     //产生异样抛出}@Transactional(propagation = Propagation.REQUIRES_NEW)public void testB(){    B(b1);  //调用B入参b1    B(b2);  //调用B入参b2}

后果:
这种情景的执行后果就是a1没有存储,而b1和b2存储胜利,因为testB的事务流传设置为REQUIRES_NEW,所以在执行testB时会开启一个新的事务,testMain中产生的异样时在testMain所开启的事务中,所以这个异样不会影响testB的事务提交,testMain中的事务会产生回滚,所以最终a1就没有存储,而b1和b2就存储胜利了。

NOT_SUPPORTED

始终以非事务形式执行,如果以后存在事务,则挂起以后事务

@Transactional(propagation = Propagation.REQUIRED)public void testMain(){    A(a1);  //调用A入参a1    testB();    //调用testB}@Transactional(propagation =Propagation.NOT_SUPPORTED)public void testB(){    B(b1);  //调用B入参b1    throw Exception;     //产生异样抛出    B(b2);  //调用B入参b2}

后果:
a1和b2没有存储,而b1存储胜利。testMain有事务,而testB不应用事务,所以执行中testB的存储b1胜利,而后抛出异样,此时testMain检测到异样事务产生回滚,然而因为testB不在事务中,所以只有testMain的存储a1产生了回滚,最终只有b1存储胜利,而a1和b1都没有存储

NEVER

不应用事务,如果以后事务存在,则抛出异样

@Transactional(propagation = Propagation.REQUIRED)public void testMain(){    A(a1);  //调用A入参a1    testB();    //调用testB}@Transactional(propagation = Propagation.NEVER)public void testB(){    B(b1);  //调用B入参b1    B(b2);  //调用B入参b2}

后果:
该场景执行,间接抛出事务异样,且不会有数据存储到数据库。因为testMain事务流传类型为REQUIRED,所以testMain是运行在事务中,而testB事务流传类型为NEVER,所以testB不会执行而是间接抛出事务异样,此时testMain检测到异样就产生了回滚,所以最终数据库不会有数据存入。

NESTED

如果以后事务存在,则在嵌套事务中执行,NESTED是以后存在事务时(咱们把以后事务称之为父事务)会开启一个嵌套事务(称之为一个子事务)。
在NESTED状况下父事务回滚时,子事务也会回滚
子事务回滚,父事务不受影响

@Transactional(propagation = Propagation.REQUIRED)public void testMain(){    A(a1);  //调用A入参a1    testB();    //调用testB    throw Exception;     //产生异样抛出}@Transactional(propagation = Propagation.NESTED)public void testB(){    B(b1);  //调用B入参b1    B(b2);  //调用B入参b2}

后果:
所有数据都不会存入数据库,因为在testMain产生异样时,父事务回滚则子事务也跟着回滚了

面试题

spring事务的原理?
spring事务的实质其实就是数据库对事务的反对,没有数据库的事务反对,spring是无奈提供事务性能的。
那么,咱们个别应用JDBC操作事务的时候,代码如下
(1)获取连贯 Connection con = DriverManager.getConnection()
(2)开启事务con.setAutoCommit(true/false);
(3)执行CRUD
(4)提交事务/回滚事务 con.commit() / con.rollback();
(5)敞开连贯 conn.close();
应用spring事务管理后,咱们能够省略步骤(2)和步骤(4),就是让AOP帮你去做这些工作。

spring什么状况下进行事务回滚?
1.事务只会对Error与RuntimeException及其子类这些异样,做出回滚。个别的Exception这些Checked异样不会产生回滚
2.当所拦挡的办法有指定异样抛出,事务才会主动进行回滚,异样被捕捉则不会回滚

spring事务什么时候生效?
1.数据库引擎不反对事务
2.没有被 Spring 治理
3.办法不是 public 的
4.本身调用问题
5.异样被捕捉
6.异样类型谬误

spring的事务隔离和数据库的事务隔离是一个概念么?
是的,如果spring定义的隔离级别和数据库的不一样,则以spring定义的为准

spring事务管制放在service层,在service办法中一个办法调用service中的另一个办法,默认开启几个事务?
考验spring的事务PROPAGATION_REQUIRED级别的流传行为,如果外层有事务,则以后事务退出到外层事务,一块提交,一块回滚。如果外层没有事务,新建一个事务执行。

参考:
带你读懂Spring 事务——事务的流传机制
面试官:来,讲讲spring事务有哪些坑?