package com.bc.exam.config;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.*;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;


/**
 * @Description 描述:
 * @Author A贾宇婷034244310
 * @Date 20260615
 */
@Aspect
@Configuration
public class TransactionAopConfig {
    @Resource
    private PlatformTransactionManager transactionManager;

    @Pointcut("execution(* com.bc.exam.modules.*.service.impl.*.*(..))")
    public String transactionPoint(){
        return "execution(* com.bc.exam.modules.*.service.impl.*.*(..))";
    }
    /**
     * 事务管理配置
     */
    @Bean("txAdvice")
    public TransactionInterceptor txAdvice() {
        // 事务管理规则，承载需要进行事务管理的方法名（模糊匹配）及设置的事务管理属性
        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();

        /* 配置增C删D改U INSERT DELETE UPDATE */
        RuleBasedTransactionAttribute ruleForCUD = new RuleBasedTransactionAttribute();
        ruleForCUD.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class))); // 抛出异常 -> 事务回滚
        ruleForCUD.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);  // 事务传播行为: 已存在事务则加入事务，否则新建事务
        ruleForCUD.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);   // 事务隔离级别：读已提交，索引没有命中时时放行锁

        /* 配置读R SELECT */
        RuleBasedTransactionAttribute ruleForR = new RuleBasedTransactionAttribute();
        ruleForR.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class))); // 抛出异常 -> 事务回滚
        ruleForR.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);   // 事务传播行为: 已存在事务则加入，不存在就不使用事务
        ruleForR.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED); // 事务隔离级别：读已提交，索引没有命中时时放行锁
        ruleForR.setReadOnly(true); // 只读，数据库会对只读的操作进行优化

        // 需要事务管理的方法，模糊匹配
        Map<String, TransactionAttribute> txMap = new HashMap<>();
        /* 增 */
        txMap.put("insert*", ruleForCUD);
        txMap.put("add*", ruleForCUD);
        txMap.put("create*", ruleForCUD);
        txMap.put("new*", ruleForCUD);
        txMap.put("quick*", ruleForCUD);
        txMap.put("init*", ruleForCUD);
        /* 改 */
        //        txMap.put("update*", ruleForCUD);
        txMap.put("up*", ruleForCUD);
        txMap.put("set*", ruleForCUD);
        txMap.put("alter*", ruleForCUD);
        /* 删除 */
        txMap.put("remove*", ruleForCUD);
        txMap.put("delete*", ruleForCUD);
        txMap.put("del*", ruleForCUD);
        /* 查 */
        txMap.put("query*", ruleForR);
        txMap.put("select*", ruleForR);
        txMap.put("get*", ruleForR);
        txMap.put("find*", ruleForR);

        source.setNameMap(txMap);
        // 实例化事务拦截器
        return new TransactionInterceptor(transactionManager, source);
    }

    /**
     * 设置切面规则，容器自动注入
     */
    @Bean
    public Advisor advisor() {
        // 声明切点要切入的面
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        // 设置需要被拦截的路径
        pointcut.setExpression(transactionPoint());
        // 设置切面和配置好的事务管理
        return new DefaultPointcutAdvisor(pointcut, txAdvice());
    }
}
