You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot+Druid下自定义@myTransactional注解的实现方案咨询

问题描述

当前手动事务管理代码如下:

public void exec(){
   Connection conn = null;
   try{
       Connection conn = getConnection();
       save(user1,conn);
       update(school,conn);
       delete(home,conn);
       conn.commit()
    }catch(Exception e)
    {
       conn.rollback();
    }finally{
      conn.close();
   }
}
getConnection(){
    conn = dataSource.getConnection();
    conn.setAutoCommit(false);
}
save(entity,conn){
   String SQL = createSQL(entity);
   stmt = conn.prepareStatement(SQL,ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
   
}

期望简化为如下形式:

@myTransactional
public void exec(){
   save(user1);
   update(school);
   delete(home);
}

使用Spring Boot框架,仅依赖Druid,未使用JdbcTemplate。咨询以下问题:

  1. 在自定义@myTransactional注解中如何获取Connection?
  2. 如何执行提交或回滚操作?
  3. 是否有其他实现方案?

解决方案

一、自定义@myTransactional注解获取Connection的方式

核心是通过ThreadLocal绑定当前线程的Connection,结合Spring AOP实现方法拦截:

  1. 先定义自定义注解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface myTransactional {
}
  1. 编写AOP切面类,用ThreadLocal存储线程专属Connection:
@Component
@Aspect
public class TransactionAspect {
    @Autowired
    private DruidDataSource dataSource;
    // ThreadLocal确保同一事务内的所有方法共享同一个Connection
    private ThreadLocal<Connection> connThreadLocal = new ThreadLocal<>();

    @Pointcut("@annotation(com.xxx.myTransactional)")
    public void transactionPointcut() {}

    @Around("transactionPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Connection conn = null;
        try {
            // 从Druid获取连接并关闭自动提交
            conn = dataSource.getConnection();
            conn.setAutoCommit(false);
            // 将连接存入ThreadLocal
            connThreadLocal.set(conn);
            // 执行目标业务方法
            Object result = joinPoint.proceed();
            return result;
        } catch (Throwable e) {
            throw e;
        } finally {
            // 后续提交/回滚、关闭连接逻辑放在这里,下文详述
        }
    }

    // 提供给save/update/delete方法获取当前线程Connection的入口
    public Connection getCurrentConn() {
        return connThreadLocal.get();
    }
}
  1. 修改业务方法,从切面类获取Connection,无需手动传入:
@Autowired
private TransactionAspect transactionAspect;

public void save(User user) {
    Connection conn = transactionAspect.getCurrentConn();
    String SQL = createSQL(user);
    try (PreparedStatement stmt = conn.prepareStatement(SQL, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)) {
        stmt.executeUpdate();
    } catch (SQLException e) {
        throw new RuntimeException(e);
    }
}

二、提交/回滚操作的实现

在AOP切面的环绕通知中完成事务的提交与回滚:

@Around("transactionPointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    Connection conn = null;
    try {
        conn = dataSource.getConnection();
        conn.setAutoCommit(false);
        connThreadLocal.set(conn);
        Object result = joinPoint.proceed();
        // 方法正常执行,提交事务
        conn.commit();
        return result;
    } catch (Throwable e) {
        // 方法抛出异常,回滚事务
        if (conn != null) {
            try {
                conn.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }
        throw e;
    } finally {
        // 释放连接并清除ThreadLocal,避免内存泄漏
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        connThreadLocal.remove();
    }
}

三、其他实现方案

方案1:直接使用Spring原生@Transactional

Spring原生事务管理完全支持Druid数据源,无需自定义注解:

  1. 配置Druid数据源(application.yml):
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    url: jdbc:mysql://localhost:3306/test_db
    username: root
    password: your_password
  1. 在启动类或配置类上添加@EnableTransactionManagement开启事务支持
  2. 直接在业务方法上标注@Transactional,Spring会自动处理Connection绑定、事务提交/回滚:
@Transactional
public void exec(){
   save(user1);
   update(school);
   delete(home);
}

方案2:使用Spring TransactionTemplate编程式事务

如果偏好编程式风格,可以用TransactionTemplate:

@Autowired
private TransactionTemplate transactionTemplate;

public void exec() {
    transactionTemplate.execute(status -> {
        save(user1);
        update(school);
        delete(home);
        return null;
    });
}

需提前配置TransactionTemplate:

@Bean
public TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) {
    return new TransactionTemplate(transactionManager);
}

内容的提问来源于stack exchange,提问作者ighack

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 22:57:50