事物的传播机制

目录

1、事务的传播机制

2、测试

2.1、准备测试方法

2.2、事务传播机制的测试

2.2.1、REQUIRED

2.2.2、NOT_SUPPORTED

2.2.3、REQUIRES_NEW

2.2.4、MANDATORY

2.2.5、NEVER

2.2.6、SUPPORTS

2.2.7、NESTED



事务传播机制:就是事务在多个方法的调用中是如何传递的,是重新创建事务还是使用父方法的事务?父方法的回滚对子方法的事务是否有影响?这些都是可以通过事务传播机制来决定的。

以spring的事务传播机制为例子:

Spring事务机制:主要包括声明式事务和编程式事务,此处侧重讲解声明式事务,编程式事务在实际开发中得不到广泛使用,仅供学习参考。

Spring声明式事务让我们从复杂的事务处理中得到解脱。使得我们再也无需要去处理获得连接、关闭连接、事务提交和回滚等这些操作。再也无需要我们在与事务相关的方法中处理大量的try…catch…finally代码。我们在使用Spring声明式事务时,有一个非常重要的概念就是事务属性。事务属性通常由事务的传播行为事务的隔离级别事务的超时值事务只读标志组成。我们在进行事务划分时,需要进行事务定义,也就是配置事务的属性。

 嵌套事务: 一个非常重要的概念就是内层事务依赖于外层事务。外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚。

1、事务的传播机制

事务的传播机制定义在TransactionDefinition接口中,我们也可以通过枚举类Propagation类调用,下面我也附上两个类的源码

  • Propagation.REQUIRED:支持当前事务,如果当前没有事务,则新建一个事务,默认使用这种,也是最常见的 。
  • Propagation.SUPPORTS:支持当前事务,如果没有事务,就以非事务(即数据库事物)的方式执行。
  • Propagation.MANDATORY:支持当前事务,如果没有事务,就抛出异常.
  • Propagation.REQUIRES_NEW:新建事务,如果当前存在事务,就把当前事务挂起。
  • Propagation.NOT_SUPPORTED:以非事务的方式执行操作,如果当前存在事务,就把当前事务挂起.
  • Propagation.NEVER:以非事务的方式执行,如果当前存在事务,则会抛出异常.
  • Propagation.NESTED:如果当前事务存在,则执行嵌套事务,否则执行类似REQUIRED的操作.

2、测试

2.1、准备测试方法

  • 开启事务 配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
	
	<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
  • 创建实体类User
package com.example.demo.testspringtransaction;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* @author 
* @since  2021年1月13日 下午3:36:34
* @version 1.0
* 
*  	@Data  :注解在类上;提供类所有属性的 getting 和 setting 方法,此外还提供了equals、canEqual、hashCode、toString 方法
*	@Setter:注解在属性上;为属性提供 setting 方法
*	@Getter:注解在属性上;为属性提供 getting 方法
*	@Log4j :注解在类上;为类提供一个 属性名为log 的 log4j 日志对象
*	@NoArgsConstructor:注解在类上;为类提供一个无参的构造方法
*	@AllArgsConstructor:注解在类上;为类提供一个全参的构造方法
*
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
	
	private String id;
	private String name;
}
  • 创建service接口UserService1 、UserService2 
package com.example.demo.testspringtransaction;
/**
* @author 
* @since  2021年1月13日 下午3:48:27
* @version 1.0
*
*/
public interface UserService1 {
	
	public void save(User user);
	public void update(User user);

}
package com.example.demo.testspringtransaction;
/**
* @author 
* @since  2021年1月13日 下午3:48:27
* @version 1.0
*
*/
public interface UserService2 {

	public void delete(String id);
	
}
  • 创建service实现类:UserService1Impl 、UserService2Impl
package com.example.demo.testspringtransaction;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
* @author  
* @since  2021年1月13日 下午3:56:02
* @version 1.0
*
*/
@Service
@Transactional(propagation=Propagation.REQUIRED)
public class UserService1Impl implements UserService1 {
	
	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	@Autowired
	private UserService2 userService2;

	@Override
	public void save(User user) {
		String sql = "insert into user values(?,?)";
		jdbcTemplate.update(sql,
			new Object[]{user.getId(),user.getName()},
			new int[]{java.sql.Types.VARCHAR,java.sql.Types.VARCHAR});
		
		userService2.delete("002");
//		update(user);
//		throw new RuntimeException("error");
		
	}

	@Override
	public void update(User user) {
		String sql = "update user set name = ? where id=?";
		jdbcTemplate.update(sql, new Object[]{user.getName(),user.getId()},
				new int[]{java.sql.Types.VARCHAR,java.sql.Types.VARCHAR});
	}

}
package com.example.demo.testspringtransaction;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
* @author 
* @since  2021年1月13日 下午3:56:02
* @version 1.0
*
*/
@Service
@Transactional(propagation=Propagation.REQUIRED)
public class UserService2Impl implements UserService2 {

	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	@Override
	public void delete(String id) {
		String sql = "delete from user where id=?";
		jdbcTemplate.update(sql, id);
	}
}
  • 创建Configuration类,用于创建DataSource实现
package com.example.demo.testspringtransaction;

import java.sql.SQLException;

import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;

@Configuration
@ComponentScan(basePackages={"com.example.demo.testspringtransaction"})// 扫描UserService1实现类所在的包路径
@ImportResource(locations={"classpath:beans.xml"})// 添加事务管理
public class JdbcConfig {
 
	@Bean
	public JdbcTemplate jdbcTemplate(DataSource dataSource){
		return new JdbcTemplate(dataSource);
	}
	
	@Bean
	public DataSourceTransactionManager transactionManager(DataSource dataSource){
		return new DataSourceTransactionManager(dataSource);
	}
	
	@Bean
	public DataSource dataSource(){
		try {
			return new SimpleDriverDataSource(new com.mysql.jdbc.Driver(), "jdbc:mysql://localhost:3306/springboot", "root", "123456");
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return null;
	}
}
  • 测试类
package com.example.demo.testspringtransaction;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
* @author 
* @since  2021年1月13日 下午4:07:42
* @version 1.0
*
*/
public class Test {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(JdbcConfig.class);
		UserService1 userService1 = ac.getBean(UserService1.class);
		User user = new User("001","唐僧");
		userService1.save(user);
	}

}

2.2、事务传播机制的测试

2.2.1、REQUIRED

 定义:如果有事务则加入事务,如果没有事务,则创建一个新的(默认值)。

 注意事项:当两个方法的传播机制都是REQUIRED时,如果一旦发生回滚,两个方法都会回滚。

测试点1:将UserService1Impl和BlogService2Impl的事务传播机制都修改为@Transactional(propagation=Propagation.REQUIRED)

测试点2:将UserService1Impl事务传播机制修改为@Transactional(propagation=Propagation.NOT_SUPPORTED),UserService2Impl的仍为@Transactional(propagation=Propagation.REQUIRED)

总结:

        当UserService1Impl提供事务的时候,UserService2Impl的方法执行使用当前已有事务,不再新建事务;

        当UserService1Impl不创建事务的时候,UserService2Impl的方法执行发现没有事务可用,自己新建事务;

2.2.2、NOT_SUPPORTED

定义:不为当前方法开启事务,相当于没有Spring事务,每条执行语句单独执行,单独提交。

测试点3:将UserService1Impl和BlogService2Impl的事务传播机制都修改为:@Transactional(propagation=Propagation.NOT_SUPPORTED)

总结:

        NOT_SUPPORTED相当于没有Spring事务,每条执行语句单独执行,单独提交。 

2.2.3、REQUIRES_NEW

定义:不管是否存在事务,都创建一个新的事务,原来的方法挂起,新的方法执行完毕后,继续执行老的事务。 老事务报错,老失误回滚,并不影响新事务的提交。

测试点4将UserService1Impl事务传播机制修改为@Transactional(propagation=Propagation.REQUIRED),BlogService2Impl的改为@Transactional(propagation=Propagation.REQUIRES_NEW)

总结:

        REQUIRES_NEW为当前方法创建一个新的事务,并且当前事务先提交,然后再提交老的事务。 

2.2.4、MANDATORY

定义必须在一个已有的事务中执行,否则报错。报错时,前一个方法中的非事务处理,不回滚。

测试点5:将UserService1Impl事务传播机制修改为@Transactional(propagation=Propagation.NOT_SUPPORTED),UserService2Impl的改为@Transactional(propagation=Propagation.MANDATORY),查看是否报错。

总结:    

        MANDATORY必须在已有事务下被调用,否则报错。

        NOT_SUPPORTED执行数据库层面的事务操作,故当前测试中,insert方法成功执行,delete方法的抛错并不影响insert方法的执行。

2.2.5、NEVER

定义:必须在一个没有的事务中执行,否则报错。

测试点6将UserService1Impl事务传播机制修改为@Transactional(propagation=Propagation.REQUIRED),UserService2Impl的仍为@Transactional(propagation=Propagation.NEVER),查看是否报错。

总结:

        NEVER必须在没有事务的方法中执行,否则报错;

        save方法开启一个事务,还没来及提交发现delete方法报错,只能回滚事务。

2.2.6、SUPPORTS

定义:是否使用事务取决于调用方法是否有事务,如果有则直接用,如果没有则不使用事务。

测试点7将UserService1Impl事务传播机制修改为@Transactional(propagation=Propagation.REQUIRED),UserService2Impl的仍为@Transactional(propagation=Propagation.SUPPORTS)

测试点8将UserService1Impl事务传播机制修改为@Transactional(propagation=Propagation.NOT_SUPPORTED),UserService2Impl的仍为@Transactional(propagation=Propagation.SUPPORTS)

  总结:

        SUPPORTS类型的事务传播机制,是否使用事务取决于调用方法是否有事务,如果有则直接用,如果没有则不使用事务

2.2.7、NESTED

定义:如果当前存在事务,则在嵌套事务内执行(当前事务回滚,嵌套事务也回滚;嵌套事务回滚,不影响当前事务)。如果当前没有事务,则执行与REQUIRED类似的操作。

测试点9将UserService1Impl事务传播机制修改为@Transactional(propagation=Propagation.REQUIRED),UserService2Impl 改为@Transactional(propagation=Propagation.NESTED)

测试点10:将UserService1Impl事务传播机制修改为@Transactional(propagation=Propagation.NOT_SUPPORTED),UserService2Impl 改为@Transactional(propagation=Propagation.NESTED)

总结:

        save方法创建一个事务,则再调用delete方法时,直接在该事务的基础上创建一个嵌套事务,本质上还是同一个事务,做一次提交;

        save方法不创建事务,则调用delete方法时,直接创建一个新的事务,单独提交。

3、spring事务的五种隔离级别

目录

1、事务的传播机制

2、测试

2.1、准备测试方法

2.2、事务传播机制的测试

2.2.1、REQUIRED

2.2.2、NOT_SUPPORTED

2.2.3、REQUIRES_NEW

2.2.4、MANDATORY

2.2.5、NEVER

2.2.6、SUPPORTS

2.2.7、NESTED

3、spring事务的五种隔离级别


ISOLATION_DEFAULT:是事务管理器的默认隔离级别,使用数据库默认的隔离级别。另外四个与jdbc的隔离级别 相对应

ISOLATION_READ_UNCOMMITTED:最低的隔离级别,它允许一个事务读取另一个事务未提交的数据,会产生脏读 不可重复读,幻读

ISOLATION_READ_COMMITTED:保证一个事务修改的数据提交后另一个事务才能读取到,可以避免脏读.

ISOLATION_REPEATABLE_READ:数据库就是使用的这种隔离级别,可以避免脏读和不可重复读,但是可能出现 幻读(幻读:一个事务读取完,另一个事务提交了更新,本事务再次读取会 发现前后数据不一致,像产生了幻觉一样,所以叫幻读)

ISOLATION_SERIALIZABLE:花费代价最高也是最可开的事务隔离级别,事务被处理为顺序执行,但是这种隔离 级别会产生锁表,就是一个事务读取之后,另一个事务必须等待这个事务完成, 他才可以进行,第一个事务会将整张表锁起来,一般不会使用这种隔离级别, 性能极低!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 17
    点赞
  • 104
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring 事务传播机制指的是在事务嵌套的场景下,不同事务之间的行为表现。Spring 事务传播机制定义了一个方法在调用其他方法时如何使用事务。 Spring 事务传播机制主要有以下 7 种: 1. REQUIRED:如果当前存在事务,则加入该事务,否则新建一个事务。 2. SUPPORTS:如果当前存在事务,则加入该事务,否则以非事务方式执行。 3. MANDATORY:当前必须存在事务,否则抛出异常。 4. REQUIRES_NEW:新建一个事务,如果当前存在事务,则将当前事务挂起。 5. NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,则将当前事务挂起。 6. NEVER:以非事务方式执行操作,如果当前存在事务,则抛出异常。 7. NESTED:如果当前存在事务,则在嵌套事务内执行,否则新建一个事务。 其中,REQUIRED 是默认的传播机制。如果不指定传播机制,Spring 会默认使用 REQUIRED 传播机制。 在使用事务传播机制时,需要注意以下几点: 1. 事务传播机制只对嵌套事务有效,对于非嵌套事务,传播机制不会产生影响。 2. 事务传播机制只对使用 @Transactional 注解的方法有效。 3. 在使用嵌套事务时,需要使用支持保存点(Savepoint)的事务管理器,如 Spring 的 JtaTransactionManager。 综上所述,Spring 事务传播机制可以帮助我们更好地管理事务,避免事务嵌套带来的问题。在使用事务传播机制时,需要根据具体情况选择合适的传播机制,以便实现更好的事务管理。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值