spring boot增加事务

maven依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
        </dependency>
        <dependency>
            <groupId>com.jfinal</groupId>
            <artifactId>jfinal</artifactId>
            <version>2.2</version>
        </dependency>

添加一个AOP切面类

package com.rc.openapi.datasource;

import com.jfinal.kit.LogKit;
import com.jfinal.plugin.activerecord.ActiveRecordException;
import com.jfinal.plugin.activerecord.Config;
import com.jfinal.plugin.activerecord.DbKit;
import com.jfinal.plugin.activerecord.NestedTransactionHelpException;
import com.jfinal.plugin.activerecord.tx.TxConfig;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.transaction.NoTransactionException;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * @ClassName JFinalTxAop
 * @Author LWJ
 * @Date 2021/1/22 21:46
 * @方法说明 {事务控制}
 */
@Aspect
@Component
public class JFinalTxAop {
    /**
     * 是否可以手动提交事物,默认可以自动提交
     */
    private static boolean canCommit = true;
    /**
     * 自定义JFinal 事物注解:类上面
     *
     * @within 表示注解在类下面所有的方法
     */
    @Pointcut("@within(org.springframework.transaction.annotation.Transactional)")
    private void methodWithin() {
    }

    /**
     * 自定义JFinal 事物注解:方法上面
     *
     * @annotation 表示注解只能支持方法上
     */
    @Pointcut("@annotation(org.springframework.transaction.annotation.Transactional)")
    private void methodAnno() {
    }

    /**
     * 兼容@Transactional可以放在类上和方法上
     * 当放类上时,类中所有方法都支持事物注解,
     * 如果类上没有@Transactional,然而是放在方法上的,那么只有此方法支持事物注解
     *
     * @param pjp 切入点目标对象
     * @return 返回切入方法的返回数据
     * @throws Throwable
     */
    @Around(value = "methodWithin() || methodAnno()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        Object retVal = null;
        Config config = getConfigWithTxConfig(pjp);
        if (config == null)
            config = DbKit.getConfig();

        Connection conn = config.getThreadLocalConnection();
        // Nested transaction support
        if (conn != null) {
            try {
                if (conn.getTransactionIsolation() < getTransactionLevel(config))
                    conn.setTransactionIsolation(getTransactionLevel(config));
                retVal = pjp.proceed();
                return retVal;
            } catch (SQLException e) {
                throw new ActiveRecordException(e);
            }
        }
        Boolean autoCommit = null;
        try {
            conn = config.getConnection();
            autoCommit = conn.getAutoCommit();
            config.setThreadLocalConnection(conn);
            conn.setTransactionIsolation(getTransactionLevel(config));// conn.setTransactionIsolation(transactionLevel);
            conn.setAutoCommit(false);
            retVal = pjp.proceed();
            if (canCommit) {
                conn.commit();
            } else {
                try {
                    conn.rollback();
                } catch (Exception e1) {
                    LogKit.error(e1.getMessage(), e1);
                }
            }
        } catch (NestedTransactionHelpException e) {
            if (conn != null) try {
                conn.rollback();
            } catch (Exception e1) {
                LogKit.error(e1.getMessage(), e1);
            }
            LogKit.logNothing(e);
        } catch (Throwable t) {
            if (conn != null) try {
                conn.rollback();
            } catch (Exception e1) {
                LogKit.error(e1.getMessage(), e1);
            }
            throw t instanceof RuntimeException ? (RuntimeException) t : new ActiveRecordException(t);
        } finally {
            canCommit = true;
            try {
                if (conn != null) {
                    if (autoCommit != null)
                        conn.setAutoCommit(autoCommit);
                    conn.close();
                }
            } catch (Throwable t) {
                // can not throw exception here, otherwise the more important exception in previous catch block can not be thrown
                LogKit.error(t.getMessage(), t);
            } finally {
                // prevent memory leak
                config.removeThreadLocalConnection();
            }
        }
        return retVal;
    }

    /**
     * 获取配置的事务级别
     *
     * @param config
     * @return
     */
    protected int getTransactionLevel(Config config) {
        return config.getTransactionLevel();
    }

    /**
     * @param lwj
     * @return Config
     */
    public static Config getConfigWithTxConfig(ProceedingJoinPoint pjp) {
        MethodSignature ms = (MethodSignature) pjp.getSignature();
        Method method = ms.getMethod();
        TxConfig txConfig = method.getAnnotation(TxConfig.class);
        if (txConfig == null)
            txConfig = pjp.getTarget().getClass().getAnnotation(TxConfig.class);

        if (txConfig != null) {
            Config config = DbKit.getConfig(txConfig.value());
            if (config == null)
                throw new RuntimeException("Config not found with TxConfig: " + txConfig.value());
            return config;
        }
        return null;
    }

    public static boolean setRollbackOnly() {
        canCommit = false;
        try {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        } catch (NoTransactionException e) {
            return false;
        }
        return true;
    }
}

注意:
这个类上面要增加两个注解
@Aspect
作用是把当前类标识为一个切面供容器读取

@Component
标注一个类为Spring容器的Bean,(把普通pojo实例化到spring容器中,相当于配置文件中的)

启动类:

package com.rc.openapi;

import brave.sampler.Sampler;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Bean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableDiscoveryClient
@EnableTransactionManagement
/**
 * @author lwj
 *
 */

public class ProviderApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class, args);
    }

    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }

    @Bean
    public Sampler defaultSampler() {
        return Sampler.ALWAYS_SAMPLE;
    }
}

注意:
@EnableDiscoveryClient
是能够让注册中心能够发现,扫描到该服务

@EnableTransactionManagement
开启事务支持

service

package com.rc.openapi.service.serviceImpl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import com.rc.openapi.datasource.JFinalTxAop;
import org.springframework.stereotype.Service;

import com.rc.openapi.domain.mysql.TestMapper1;
import com.rc.openapi.domain.oracle.TestMapper2;
import com.rc.openapi.service.TestDemoService;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Transactional
@Service
public class TestDemoServiceImpl implements TestDemoService {
    @Resource
    private TestMapper2 testMapper2;
    @Resource
    private TestMapper1 testMapper1;

   

    @Override
    public void insertTest()  {
        try {
            Map<String,Object> map = new HashMap<>() ;
            map.put("name","123");
            testMapper1.insertTest(map);
   			int i = 100/1;//触发异常
        } catch (Exception e) {
            e.printStackTrace();
             throw new RuntimeException("test");
        }
       
		//或者手动回滚,不用抛出异常
		JFinalTxAop.setRollbackOnly()
    }
}

@ Transactional可以放在类上或方法上都没问题
JFinalTxAop.setRollbackOnly()和
throw new RuntimeException(“test”);

这和个时候可以不用加因为启动的是时候已经把切面类加载进去了.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值