https://blog.csdn.net/hanjiaqian/article/details/120501741

事务不生效

原理

生成了代理类,在代理类中实现事务功能。

@Service
public class A{
    @Transactinal
    public void b(){
        a();
    }
    
    public void a(){ ... }
}
 
//Spring扫描注解后,创建了另外一个代理类,并为有注解的方法插入一个startTransaction()方法:
public class proxy$A{
    A objectA = new A();
    public void b(){    
        startTransaction();
        objectA.b();
    }
 
    public void a(){    
        objectA.a(); 
    }
}
场景

1.访问权限问题

Spring 要求被代理方法必须是public

2. 方法用 final 修饰

在代理类中,无法重写该方法,添加事务功能

注意:如果某个方法是 static 的,同样无法通过动态代理,变成事务方法。

3.方法内部调用

未加注解的方法调用加注解的方法,事务失效

@Service
public class A{
    public void b(){
        a();
    }
    @Transactinal
    public void a(){ ... }
}
 
//Spring扫描注解后,创建了另外一个代理类,并为有注解的方法插入一个startTransaction()方法:
public class proxy$A{
    A objectA = new A();
    public void b(){    
        objectA.b();// 这里其实是调用的非代理类的a(),不走事务
    }
    public void a(){
        startTransaction();
        objectA.a(); 
    }
}

解决方法:

public class AopInvalidDemo {
    // @Autowired
    // private AopInvalidDemo proxy;
​
    // 方法 1
    // @TestInvalid
    public String todo() {
        // 坑:这个 this 是 代理类中的 target,不走切面
        String result = this.todo1();
​
        // 方法 2
        // 这个是代理类
        // String result = proxy.todo1();
​
        // 方法 3
        // 这个是代理类
        // AopInvalidDemo proxy = SpringUtil.getBean(AopInvalidDemo.class);
        // String result = proxy.todo1();
​
        String r = result + "_666";
        return r;
    }
    
    @TestInvalid
    public String todo1() {
        System.out.println("执行了");
        return "todo1";
    }
}

4.未被 Spring 管理

5.多线程调用

如果在不同的线程,拿到的数据库连接肯定是不一样的,所以是不同的事务。

6.表不支持事务

在 mysql5 之前,默认的数据库引擎是myisam

7.未开启事务

事务不回滚

1.错误的传播特性

2.自己吞了异常

3.手动抛了别的异常

4.自定义了回滚异常

5.嵌套事务回滚多了

大事务问题

事务中尽可能只包含必要的、最少的代码,减少耗时。

编程式事务

封装工具类:

public class TransactionHelper {
​
    @Autowired
    private PlatformTransactionManager transactionManager;
​
    @Autowired
    private ExceptionManager exceptionManager;
​
    private final Logger logger = LogUtil.getLogger(TransactionHelper.class);
​
    /**
     * 将方法封装在事务里,
     * 事务传播级别-REQUIRED
     * 隔离级别-使用数据库默认
     */
    public <T> T doInTransactionWithRequired(Supplier<T> supplier) {
        return doInTransactionWithCustom(supplier, TransactionDefinition.PROPAGATION_REQUIRED, TransactionDefinition.ISOLATION_DEFAULT);
    }
​
    /**
     * 将方法封装在事务里,
     * 事务传播级别-REQUIRES_NEW
     * 隔离级别-使用数据库默认
     */
    public <T> T doInTransactionWithRequiresNew(Supplier<T> supplier) {
        return doInTransactionWithCustom(supplier, TransactionDefinition.PROPAGATION_REQUIRES_NEW, TransactionDefinition.ISOLATION_DEFAULT);
    }
​
​
    /**
     * 将方法封装在事务里,
     * 自定义事务传播级别
     * 隔离级别-使用数据库默认
     */
    public <T> T doInTransactionWithCustom(Supplier<T> supplier, int propagationBehavior) {
        return doInTransactionWithCustom(supplier, propagationBehavior, TransactionDefinition.ISOLATION_DEFAULT);
    }
​
    /**
     * 将方法封装在事务里,
     * 自定义事务传播级别
     * 自定义隔离级别
     */
    public <T> T doInTransactionWithCustom(Supplier<T> supplier, int propagationBehavior, int isolationLevel) {
        DefaultTransactionDefinition transDefinition = new DefaultTransactionDefinition();
        transDefinition.setPropagationBehavior(propagationBehavior);
        transDefinition.setIsolationLevel(isolationLevel);
​
        TransactionStatus status = transactionManager.getTransaction(transDefinition);
        T result = null;
        Throwable executeException = null;
        try {
            result = supplier.get();
        } catch (Throwable throwable) {
            executeException = throwable;
        }
​
        boolean executeFailure = ObjectUtil.isNotNull(executeException);
        if (executeFailure) {
            // 业务代码抛异常——回滚事务
            try {
                // 如果回滚事务抛异常,为了不影响业务的异常,需要加try-catch,只打印日志,不抛出
                transactionManager.rollback(status);
            } catch (Throwable ex) {
                String msg = "数据库事务回滚失败!";
                exceptionManager.logException(msg, ex, logger);
            }
            // 将业务代码的异常重新抛出去给外部处理
            exceptionManager.rethrow(executeException);
        } else {
            // 业务代码正常执行——提交事务
            transactionManager.commit(status);
        }
​
        return result;
    }
}



我也放荡不羁爱自由!