免费商城建站平台,专业做域名的网站吗,ip下的网站吗,网站建设软件的英文在Spring事务中#xff0c;我们通常会为了控制事务粒度#xff0c;会把它进行拆分#xff0c;为了避免大事务执行太久#xff0c;占用资源太多#xff0c;导致资源利用率低的问题。
我们曾经就遇到老系统因为大事务#xff0c;把服务打死了。
问题出在一个大事务中有一…在Spring事务中我们通常会为了控制事务粒度会把它进行拆分为了避免大事务执行太久占用资源太多导致资源利用率低的问题。
我们曾经就遇到老系统因为大事务把服务打死了。
问题出在一个大事务中有一个Excel文件解析的操作有用户上传的某个文件有1百多万个空行数据。
因为这个事务一致不能结束直接导致系统崩溃。
但是要拆分事务是一个麻烦的事情要考虑事务传播机制。
无事务
我相信很多朋友都遇到过事务不生效的情况最常见的就是下面这种情况
public class ServiceA
{public void methodA(){methodB();}Transactionalpublic void methodB(){}
}我相信有朋友已经开始笑了。
不要笑相信很多朋友本能会犯这个错误因为这种方式最简单。
上面的示例事务是不会生效的因为methodB直接被调用是因为没有通过代理执行。
问题很简单但是如何快速简单的解决问题呢
有事务不回滚
有对事务传播机制比较熟悉的朋友可能要提出下面的方案了
public class ServiceA
{Transactional(propagation Propagation.SUPPORTS)public void methodA(){methodB();}Transactionalpublic void methodB(){}
}既然没有事务我加上事务不加完了SUPPORTS机制没有事务就不创建有事务就在事务中执行 然后methodB默认事务传播机制REQUIRED没有就会创建事务。
所以methodA没有事务methodB直接创建事务执行真是天才的想法啊。
问题是实际情况真是这样吗
比较遗憾不是。
会有事务吗会methodA会生成事务。
methodB会生成新的事务吗不会因为methodA已经有事务了。
会回滚吗不会有事务但是不会回滚。
和不加Transactional(propagation Propagation.SUPPORTS)相比只是会创建事务了。
为什么会出现这样的情况呢
开的的时候我以为是SUPPORTS没有回滚点的造成。
但是我发现还是存在其他没有回滚点的事务传播机制并且能够回滚
可以添加下面的代码打印看一下
System.out.println(TransactionAspectSupport.currentTransactionStatus().hasSavepoint());还有什么办法吗
换个姿势调用
很多时候我们没有得到正确的结果可能是姿势不对我们换个姿势试一试。
既然直接调用不行那我们通过ApplicationContext来调用是否就可以触发事务了呢
Component
public class ApplicationContextHolder implements ApplicationContextAware {private ApplicationContext applicationContext;Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext applicationContext;}public ApplicationContext getApplicationContext(){return this.applicationContext;}public T T getService(ClassT clazz){return applicationContext.getBean(clazz);}
}public class ServiceA
{Resourceprivate ApplicationContextHolder applicationContextHolder;public void methodA(){ServiceA service applicationContextHolder.getService(this.getClass());service.methodB();}Transactionalpublic void methodB(){}
}答案是不行因为根本没有创建事务
多种姿势结合
public class ServiceA
{Resourceprivate ApplicationContextHolder applicationContextHolder;Transactional(propagation Propagation.SUPPORTS)public void methodA(){ServiceA service applicationContextHolder.getService(this.getClass());service.methodB();}Transactionalpublic void methodB(){}
}这样可以吗
答案是可以
事务是methodA的事务并且也回滚了。
这的确解决了我们的问题但是也违背了我们的初衷将事务粒度变小。
因为绕了一大圈发现还是相当于methodA上的事务了。
那有没有什么更靠谱的解决方案呢
大概可以试一试NESTED和REQUIRES_NEW事务吧
public class ServiceA
{Transactional(readOnly true)public void methodA(){ServiceA service applicationContextHolder.getService(this.getClass());service.methodB();}Transactional(propagation Propagation.NESTED)// Transactional(propagation Propagation.REQUIRES_NEW)public void methodB(){}
}可以回滚但是
NESTED、REQUIRES_NEW都没有回滚点NESTED、REQUIRES_NEW都使用的是methodA的事务。
感觉和直接调用没有太多的区别
Service
public class ServiceA
{Resourceprivate ServiceB serviceB;public void methodA(){serviceB.methodB();}
}Service
public class ServiceB
{ // Transactional(propagation Propagation.NESTED)Transactional(propagation Propagation.REQUIRES_NEW)public void methodB(){}
}上面的方式也可以回滚
使用NESTED有回滚点使用methodA的事务使用REQUIRES_NEW会创建新事务
事务传播机制