MySql中的父事务与子事务
MySql中的父事务与子事务
事务的范围
事务的范围指的是事务的开始和结束位置。在MySQL中,事务可以通过以下语句来显式地开始和结束:
1 |
|
当在MySQL的一个事务中设置了事务隔离级别,该级别的设置将仅对当前事务有效。事务隔离级别定义了事务对数据的读取和修改的可见性和隔离程度。事务隔离级别可以通过以下语句在MySQL中设置:
1 |
|
其中,**
- READ UNCOMMITTED:允许脏读、不可重复读和幻读。
- READ COMMITTED:禁止脏读,但允许不可重复读和幻读。
- REPEATABLE READ:禁止脏读和不可重复读,但允许幻读。
- SERIALIZABLE:禁止脏读、不可重复读和幻读。
一旦设置了事务隔离级别,该级别将在当前事务中生效,其他并发的事务将继续使用各自的隔离级别。这样可以确保每个事务在进行读取和修改时都遵循指定的隔离级别,从而提供一致的数据视图和隔离性。
父事务与子事务的传递
在MySQL中,父事务和子事务之间的传递涉及到保存点(Savepoint)的概念。保存点是在事务中创建的标记,用于标识事务中的一个特定位置。通过保存点,我们可以在事务中实现更细粒度的回滚。
父事务可以创建保存点,并在子事务中回滚到保存点。这样,子事务可以恢复到保存点时的状态,包括隔离级别。父事务的隔离级别会被子事务继承,除非子事务显式地设置了自己的隔离级别。注意,并不是所有的数据库都支持保存点技术,如果不支持,通常会新建一个事务执行事务。
假设我们有两个表:Orders(订单)和 OrderItems(订单项)。在一个事务中插入一个订单和相关的订单项,并在插入订单项之后创建一个保存点。然后,启动一个子事务,在子事务中删除刚才插入的订单项,并回滚到保存点。
1 |
|
在上述示例中,父事务设置了隔离级别为 REPEATABLE READ,而子事务没有显式设置隔离级别,因此继承了父事务的隔离级别。通过回滚到保存点,子事务恢复到保存点时的隔离级别,即 REPEATABLE READ。因此,删除操作在回滚后被撤销,订单项保留在数据库中。
Spring中的事务传播行为
事务传播行为定义了事务在方法调用链中的传播方式。Spring提供了多种事务传播行为选项来实现父事务与子事务的传播。如REQUIRED、REQUIRES_NEW、NESTED等。不同的传播行为对应不同的事务行为,能够满足各种业务需求。在Spring中,事务传播行为通过AOP和动态代理实现。Spring会在方法调用前后织入事务管理的逻辑,确保事务的正确传播和管理。(这里建议去看其他专门写Spring中的事务传播行为的博客)。
然而,由于Spring的事务传播行为通过AOP和动态代理实现,有一个常见的问题是自调用方法无法进行事务传递。即当一个方法内部自调用另一个方法时,实际上是在同一个类的实例中进行方法调用,而不是通过代理对象。因此,事务管理的拦截器无法拦截自调用方法,事务传播行为无法被应用。
1 |
|
在上述示例中,doSomething()方法是一个事务方法,它调用了自身的doSomethingElse()方法。由于自调用无法进行事务传递,doSomethingElse()方法的事务传播行为将无效。
为了解决这个问题,有两种方式:
- 将doSomethingElse()方法提取到一个独立的Bean中,并通过依赖注入的方式进行调用。这样,doSomethingElse()方法将通过代理对象进行调用,事务传播行为将得到正确应用。
- 将doSomethingElse()中加入从Spring容器中直接取出代理Bean的操作代码,这样会对Spring Api造成强依赖。
总结
在使用父事务与子事务时,需了解其原理。我们在日常开发中通常是直接使用第三方框架来调用这些事务,如Spring。