Spring事务学习笔记

前言

为啥本渣渣会忽然学习Spring事务隔离级别以及传播呢?
在昨天一位同事吐槽说,更新后查询到的是旧数据,so本渣渣决定搞个明白。

案发现场

在这里插入图片描述

然后我就尝试了一下 save*(查->update->查),还有xx(查->update->查);

结果

我们数据库是RC级别

第一种情况:查到旧数据,更新后数据库后navicat没有看到更新的数据,查询查到旧数据

第二种情况:查到旧数据,更新后数据库后navicat看到更新的数据,查询查到旧数据(而且还命中缓存了)

也就是第一种情况update的时候是没有提交的。

导致的原因

show you the code

@Getter
@Setter
@Configuration
public class TransactionConfiguration {
	private static final String CUSTOM_PLATFORM_TRANSACTION_MANAGER_NAME = "platformTransactionManager";
	private static final String CUSTOM_TRANSACTION_INTERCEPTOR_NAME = "customTransactionInterceptor";
	private static final String CUSTOM_BEAN_NAME_AUTO_PROXY_CREATOR_NAME = "beanNameAutoProxyCreator";

	/**
	 * 默认的只读事务
	 */
	private static final String[] DEFAULT_READ_ONLY_METHOD_RULE_TRANSACTION_ATTRIBUTES = { "get*", "count*", "find*",
					"query*", "select*", "list*", "*", };
	/**
	 * 默认只对 "*Service" , "*ServiceImpl" Bean 进行事务处理,"*"表示模糊匹配, 比如 :
	 * userService,orderServiceImpl
	 */
	private static final String[] DEFAULT_TRANSACTION_BEAN_NAMES = { "*Service", "*ServiceImpl" };
	/**
	 * 可传播事务配置
	 */
	private static final String[] DEFAULT_REQUIRED_METHOD_RULE_TRANSACTION_ATTRIBUTES = { "add*", "save*", "insert*",
			"delete*", "update*", "edit*", "batch*", "create*", "remove*", };

	/**
	 * 自定义事务 BeanName 拦截
	 */
	private String[] customTransactionBeanNames = {};
	/**
	 * 自定义方法名的事务属性相关联,可以使用通配符(*)字符关联相同的事务属性的设置方法; 只读事务
	 */
	private String[] customReadOnlyMethodRuleTransactionAttributes = {};
	/**
	 * 自定义方法名的事务属性相关联,可以使用通配符(*)字符关联相同的事务属性的设置方法; 传播事务(默认的)
	 * {@link org.springframework.transaction.annotation.Propagation#REQUIRED}
	 */
	private String[] customRequiredMethodRuleTransactionAttributes = {};

	@Autowired
	@Qualifier(value="druidDataSource")
	private DataSource dataSource;

	@Bean(name = CUSTOM_PLATFORM_TRANSACTION_MANAGER_NAME)
	public PlatformTransactionManager platformTransactionManager() {
		return new DataSourceTransactionManager(this.dataSource);
	}

	/**
	 * 配置事务拦截器,注意:transactionInterceptor 名称的 bean 可能已经存在,导致该生成 bean
	 * 的方法不能执行,所以定义成另外一个名字
	 *
	 * @param platformTransactionManager
	 *            事务管理器
	 * @return
	 */
	@Bean(name = CUSTOM_TRANSACTION_INTERCEPTOR_NAME)
	public TransactionInterceptor customTransactionInterceptor(
			@Qualifier(CUSTOM_PLATFORM_TRANSACTION_MANAGER_NAME) PlatformTransactionManager platformTransactionManager) {

		NameMatchTransactionAttributeSource transactionAttributeSource = new NameMatchTransactionAttributeSource();
		RuleBasedTransactionAttribute readOnly = this.readOnlyTransactionRule();
		RuleBasedTransactionAttribute required = this.requiredTransactionRule();
		// 默认的只读事务配置

		for (String methodName : DEFAULT_READ_ONLY_METHOD_RULE_TRANSACTION_ATTRIBUTES) {
			transactionAttributeSource.addTransactionalMethod(methodName, readOnly);
		}

		// 定制的只读事务配置
		for (String methodName : customReadOnlyMethodRuleTransactionAttributes) {
			transactionAttributeSource.addTransactionalMethod(methodName, readOnly);
		}

		// 默认的传播事务配置
		for (String methodName : DEFAULT_REQUIRED_METHOD_RULE_TRANSACTION_ATTRIBUTES) {
			transactionAttributeSource.addTransactionalMethod(methodName, required);
		}

		// 定制的传播事务配置
		for (String methodName : customRequiredMethodRuleTransactionAttributes) {
			transactionAttributeSource.addTransactionalMethod(methodName, required);
		}

		return new TransactionInterceptor(platformTransactionManager, transactionAttributeSource);
	}

	/**
	 * 当前存在事务就使用当前事务,当前不存在事务就创建一个新的事务
	 * {@link org.springframework.transaction.annotation.Propagation#REQUIRED}
	 */
	private RuleBasedTransactionAttribute requiredTransactionRule() {
		RuleBasedTransactionAttribute required = new RuleBasedTransactionAttribute();
		required.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
		required.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
		required.setTimeout(TransactionDefinition.TIMEOUT_DEFAULT);

		return required;
	}

	/**
	 * 只读事务
	 * {@link org.springframework.transaction.annotation.Propagation#NOT_SUPPORTED}
	 */
	private RuleBasedTransactionAttribute readOnlyTransactionRule() {
		RuleBasedTransactionAttribute readOnly = new RuleBasedTransactionAttribute();
		readOnly.setReadOnly(true);
		readOnly.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);

		return readOnly;
	}

	/**
	 * 配置事务拦截
	 * <p>
	 * {@link #customTransactionInterceptor(PlatformTransactionManager)}
	 */
	@Bean(name = CUSTOM_BEAN_NAME_AUTO_PROXY_CREATOR_NAME)
	public BeanNameAutoProxyCreator customTransactionBeanNameAutoProxyCreator() {
		BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
		// 设置定制的事务拦截器
		beanNameAutoProxyCreator.setInterceptorNames(CUSTOM_TRANSACTION_INTERCEPTOR_NAME);

		// 默认 + 定制
		String[] unions = ArrayUtils.addAll(DEFAULT_TRANSACTION_BEAN_NAMES, customTransactionBeanNames);
		beanNameAutoProxyCreator.setBeanNames(unions);
		beanNameAutoProxyCreator.setProxyTargetClass(true);

		return beanNameAutoProxyCreator;
	}
}

这一块在网上也是随手可以搜到的,也就是大家无脑式copy过来后就使用,西西~

分析

上面那一坨代码,有点像xml的配置事务。也就是以方法名去匹配,然后加事务。

那这样的话,再来看下之前那两种情况导致的原因。

第一种情况的原因

save开了一个默认事务,然后在get的时候,事务挂起。update又恢复原来的事务,get又挂起,然后提交。

第二种情况的原因

普通方法是不开启事务的,然后get正常跑,update开启一个事务,get这里是不会挂起update事务的,应该算是子事务,这个时候,update提交事务了。get命中缓存,查到旧数据。

Spring事务传播以及隔离级别学习

spring.io官网走起

Data Access

spring事务级别

Enum Propagation
在这里插入图片描述
PROPAGATION_REQUIRED

默认隔离级别
如果当前有事务则,用当前事务。没有的话创建一个。
在这里插入图片描述
注意点

当内层函数出现问题回滚,将导致外层函数一起回滚。

PROPAGATION_REQUIRES_NEW

总是新建事务。

在这里插入图片描述
注意点

互相不影响,事务回滚

PROPAGATION_NESTED

事务嵌套。
老母猪戴套,一个又一个,啊哈哈。
就是一个事务里头,又有另一个事务。外头大事务回滚会导致小事务回滚,但是小事务回滚不影响大事务执行。

看下只读的配置

在这里插入图片描述

发布了212 篇原创文章 · 获赞 30 · 访问量 19万+

猜你喜欢

转载自blog.csdn.net/weixin_38336658/article/details/103976888