分为两种:一种是编程式事务,一种是声明式事务。
顾名思义,编程式事务是指通过代码去实现事务管理,这里不做过多说明。
另一种是声明式事务,分为两种情况01:一种是通过传统xml方式配置,02:使用@Transactional注解方式配置,这是主要讲解的是通过注解方式配置。因为在springboot项目中,会自动配置DataSourceTransactionManager,我们只需要在对应的方法上或者类上加上@Transactional就会自动接入到spring的事务中,让spring管理,只有代理类的事务才会被spring管理起来。默认情况下只有运行时异常和error的时候事务才会回滚。
如下图所示,我这边本地调用接口修改数据库张三口袋里面的金额,并且启用了事务管理,抛出RuntimeExecption。这时我们调用接口,我们可以看到事务生效了,数据库里面值并没有发生改变。但是,当我们把抛出的异常改为
1、throw new SQLTimeoutException(); 调用接口的时候,发现数据库张三的金额被改变了,事务没起作用,明明开启了事务,但是没起作用,这是为什么呢?
2、在我们需要执行事务的方法,如果对异常进行抛出,并且我们手动捕获了这个异常的话,这时候事务也不会起作用的。如下图所示:
3、@Transactional注解只对方法名为pubic的才生效,编译器中不是public的方法会提示错误,对其他事务不会生效。
4、默认情况下,只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰。有事务注解修饰的方法调用类中其他非事务的update操作,非事务的方法在发生异常或者错误时不会随着主方法一起回滚。
1:Spring的事务管理默认是针对Error异常和RuntimeException异常以及其子类进行事务回滚。对RuntimeException并不需要抛出,Error不需要抛出异常、也不进行捕获。所以我们上面用到的SQLTimeoutException()并不属于这两者之间,我们需要手动回滚异常,在@Transactional注解里面指定回滚异常类型即可,我这里举一个例子@Transactional(rollbackFor = Exception.class)
2: 我们在需要执行的sercvice里面不应该主动捕获异常,这会导致我们事务不生效,应该继续往上抛,在controller层捕获即可,这样事务也生效了,异常也捕获了。
3:@Transaction注解只对方法名为pubic的才生效,其他事务不会生效。顾名思义,也就是说使用了@Transaction注解的,只能是public。因为只有@Transaction注解只有被其他方法调用才生效的,能被其他方法调用的方法,只能是public。
4:我们在使用事务注解的时候,尽量不要在类上面使用,这会使得类里面的所有方法都会有事务进行处理。比如说,我们一些方法只做查询操作,我们就没有必要再进行事务,我们应该在需要事务处理的方法上面加事务,并且指定回滚的异常类型。
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@EventListener
public @interface TransactionalEventListener {
// 指定当前标注方法处理事务的类型
TransactionPhase phase() default TransactionPhase.AFTER_COMMIT;
// 用于指定当前方法如果没有事务,是否执行相应的事务事件监听器
boolean fallbackExecution() default false;
// 与classes属性一样,指定了当前事件传入的参数类型,指定了这个参数之后就可以在监听方法上
// 直接什么一个这个参数了
@AliasFor(annotation = EventListener.class, attribute = "classes")
Class>[] value() default {};
// 作用于value属性一样,用于指定当前监听方法的参数类型
@AliasFor(annotation = EventListener.class, attribute = "classes")
Class>[] classes() default {};
// 这个属性使用Spring Expression Language对目标类和方法进行匹配,对于不匹配的方法将会过滤掉
String condition() default "";
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.transaction.interceptor;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Properties;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.lang.Nullable;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.interceptor.TransactionAspectSupport.InvocationCallback;
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
public TransactionInterceptor() {
}
public TransactionInterceptor(PlatformTransactionManager ptm, Properties attributes) {
this.setTransactionManager(ptm);
this.setTransactionAttributes(attributes);
}
public TransactionInterceptor(PlatformTransactionManager ptm, TransactionAttributeSource tas) {
this.setTransactionManager(ptm);
this.setTransactionAttributeSource(tas);
}
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
Class> targetClass = invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null;
Method var10001 = invocation.getMethod();
invocation.getClass();
return this.invokeWithinTransaction(var10001, targetClass, invocation::proceed);
}
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
oos.writeObject(this.getTransactionManagerBeanName());
oos.writeObject(this.getTransactionManager());
oos.writeObject(this.getTransactionAttributeSource());
oos.writeObject(this.getBeanFactory());
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
this.setTransactionManagerBeanName((String)ois.readObject());
this.setTransactionManager((PlatformTransactionManager)ois.readObject());
this.setTransactionAttributeSource((TransactionAttributeSource)ois.readObject());
this.setBeanFactory((BeanFactory)ois.readObject());
}
}
protected Object invokeWithinTransaction(Method method, Class> targetClass, final InvocationCallback invocation)
throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
//开启事务
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
//方法调用
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
//回滚事务
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
//提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
try {
Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
new TransactionCallback