前言:
声明式事务缺点:细粒度中等,开发接口时要考虑事务场景,12种事务场景用不好还很多坑,费时费力
编程式事务:细粒度比较细,相对比声明式事务,编程式事务不需要考虑所谓的12种场景,能避开一些不必要的坑
切面试事务:细粒度比较粗,比较符合约定大于配置的理念,开发过程中只考虑写业务逻辑不必要关心事务,提高开发效率
推荐:如果公司团队比较规范切面事务会好点,如果是小的公司一些杂的项目大家得过且过没有约定的话,建议使用编程式事务
SpringBoot声明式事务
声明式事务@Transactional可以使用在类上,也可以使用在public方法上. 如果是使用在类上,则是对所有的public方法都开启事务,如果类和方法上都有则方法上的事务生效
可以在类上使用
@Transactional(rollbackFor=Exception.class)
public class TransactionServiceImpl implements TransactionService {
}
工作中声明式事务用的比较多的还是在方法上使用,因为声明事务的使用场景有12种
@Override
@Transactional(rollbackFor=Exception.class)
public void t1(Student one) {
}
缺点:开发接口时要考虑事务场景,12种事务场景用不好还很多坑,费时费力
SpringBoot编程式事务
编程式事务
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionCallback;
/**
* @program: wym-parent
* @description: 编程式事务
* @author: 尉一民
* @create: 2023-02-28 09:28
@Component
public class TransactionTemplates extends DefaultTransactionDefinition implements InitializingBean {
public static final Logger logger = LoggerFactory.getLogger(TransactionTemplates.class);
/**
* 事务管理器
*/
@Autowired
private PlatformTransactionManager transactionManager;
@Override
public void afterPropertiesSet() {
// 校验管理器是否被spring注入
if (this.transactionManager == null) {
throw new IllegalArgumentException("Property 'transactionManager' is required");
}
}
/**
* 事务执行器
*
* @param action
* @param <T>
* @return
*/
@Transactional
public <T> T execute(TransactionCallback<T> action) {
TransactionStatus status = this.transactionManager.getTransaction(this);
T result = null;
try {
result = action.doInTransaction(status);
} catch (Exception e) {
// 事务回滚
this.transactionManager.rollback(status);
logger.error("事务执行异常", e);
return result;
}
// 事务提交
this.transactionManager.commit(status);
return result;
}
}
使用方式
在需要的地方注入TransactionTemplates
@Resource
private TransactionTemplates transactionTemplates;
然后在代码中使用
Boolean execute = transactionTemplates.execute(status -> {
//写自己的数据库crud业务
return Boolean.TRUE;
});
SpringBoot切面式事务
此种方式基于AOP功能,所以需要添加
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
写配置类
import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;
/**
* 事务配置
*
* @author lizhixiao
*/
@Aspect
@Configuration
public class TransactionAdviceConfig {
//切面路径
private static final String AOP_POINTCUT_EXPRESSION = "execution (* com.wym..service..*.*(..)) or execution (* com.wym..module..*.*(..))";
@Autowired
private TransactionManager transactionManager;
@Bean
public TransactionInterceptor txAdvice() {
DefaultTransactionAttribute txAttrRequired = new DefaultTransactionAttribute();
txAttrRequired.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
DefaultTransactionAttribute txAttrRequiredReadonly = new DefaultTransactionAttribute();
txAttrRequiredReadonly.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
txAttrRequiredReadonly.setReadOnly(true);
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
source.addTransactionalMethod("add*", txAttrRequired);
source.addTransactionalMethod("insert*", txAttrRequired);
source.addTransactionalMethod("create*", txAttrRequired);
source.addTransactionalMethod("save*", txAttrRequired);
source.addTransactionalMethod("delete*", txAttrRequired);
source.addTransactionalMethod("remove*", txAttrRequired);
source.addTransactionalMethod("update*", txAttrRequired);
source.addTransactionalMethod("merge*", txAttrRequired);
source.addTransactionalMethod("modify*", txAttrRequired);
source.addTransactionalMethod("exec*", txAttrRequired);
source.addTransactionalMethod("set*", txAttrRequired);
source.addTransactionalMethod("*", txAttrRequiredReadonly);
return new TransactionInterceptor(transactionManager, source);
}
@Bean
public Advisor txAdviceAdvisor() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
return new DefaultPointcutAdvisor(pointcut, txAdvice());
}
}
使用时在方法名要和source中配置的前缀相匹配,列如add,update,等