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

不使用Spring @Transactional,如何在JAX-RS中管理事务?

当然可以!不用Spring也能给你的Jersey(JAX-RS)RESTful服务添加事务支持,下面是几个实用的方案,完全不依赖Spring生态:

方案1:使用JTA(Java Transaction API)手动管理事务

JTA是Java EE的标准事务API,几乎所有Java EE应用服务器(比如WildFly、GlassFish、TomEE)都自带支持。如果用的是轻量容器(如Tomcat),也可以通过第三方JTA实现(比如Atomikos、Bitronix)来启用。

核心思路是注入UserTransaction,在资源方法中手动控制事务的开启、提交和回滚:

import javax.transaction.UserTransaction;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.inject.Inject;
import javax.ws.rs.WebApplicationException;

@Path("/orders")
public class OrderResource {

    @Inject
    private UserTransaction utx;

    @Inject
    private OrderRepository orderRepository;

    @POST
    public void createOrder(Order order) {
        try {
            // 开启事务
            utx.begin();
            
            // 执行数据库操作
            orderRepository.save(order);
            // 可以添加其他关联操作,比如更新库存
            
            // 提交事务
            utx.commit();
        } catch (Exception e) {
            // 异常时回滚事务
            try {
                if (utx.getStatus() == javax.transaction.Status.STATUS_ACTIVE) {
                    utx.rollback();
                }
            } catch (Exception rollbackEx) {
                rollbackEx.printStackTrace();
            }
            throw new WebApplicationException("事务执行失败", e);
        }
    }
}
方案2:利用Java EE容器管理事务(CMT)

如果你的应用运行在Java EE兼容的容器中,还可以使用容器管理事务(Container-Managed Transactions),不用手动写事务控制代码,容器会自动帮你处理事务的生命周期。

这里要注意,我们用的是Java EE标准的javax.transaction.Transactional注解,不是Spring的org.springframework.transaction.annotation.Transactional,完全不依赖Spring:

import javax.transaction.Transactional;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.inject.Inject;

@Path("/orders")
public class OrderResource {

    @Inject
    private OrderRepository orderRepository;

    @POST
    // 指定事务传播行为,这里用REQUIRED表示如果没有事务就新建一个
    @Transactional(Transactional.TxType.REQUIRED)
    public void createOrder(Order order) {
        orderRepository.save(order);
        // 其他数据库操作,容器会自动在方法结束时提交事务,异常时回滚
    }
}
方案3:手动管理JDBC事务

如果你的服务直接使用JDBC连接,也可以完全手动控制事务,不需要任何框架支持。这种方式最底层,适合简单场景:

import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.sql.DataSource;
import javax.inject.Inject;
import javax.ws.rs.WebApplicationException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

@Path("/orders")
public class OrderResource {

    @Inject
    private DataSource dataSource;

    @POST
    public void createOrder(Order order) {
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            conn.setAutoCommit(false); // 关闭自动提交,开启事务

            // 执行插入操作
            String insertSql = "INSERT INTO orders (id, name, amount) VALUES (?, ?, ?)";
            try (PreparedStatement stmt = conn.prepareStatement(insertSql)) {
                stmt.setInt(1, order.getId());
                stmt.setString(2, order.getName());
                stmt.setBigDecimal(3, order.getAmount());
                stmt.executeUpdate();
            }

            // 提交事务
            conn.commit();
        } catch (SQLException e) {
            // 异常回滚
            if (conn != null) {
                try {
                    conn.rollback();
                } catch (SQLException rollbackEx) {
                    rollbackEx.printStackTrace();
                }
            }
            throw new WebApplicationException("创建订单失败", e);
        } finally {
            // 关闭连接
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

这种方式代码有点繁琐,你可以自己封装一个事务模板类来复用事务控制逻辑,减少重复代码。

方案4:用AspectJ实现声明式事务

如果你想实现类似Spring @Transactional的声明式事务,但又不想用Spring,可以用原生AspectJ来织入事务切面。

首先自定义一个事务注解:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTransactional {
}

然后编写AspectJ切面,拦截标注了@MyTransactional的方法,自动处理事务:

import javax.transaction.UserTransaction;
import javax.inject.Inject;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class TransactionAspect {

    @Inject
    private UserTransaction utx;

    @Around("@annotation(MyTransactional)")
    public Object handleTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
        try {
            utx.begin();
            Object result = joinPoint.proceed(); // 执行目标方法
            utx.commit();
            return result;
        } catch (Exception e) {
            if (utx.getStatus() == javax.transaction.Status.STATUS_ACTIVE) {
                utx.rollback();
            }
            throw e;
        }
    }
}

最后在你的资源方法上标注@MyTransactional即可:

@POST
@MyTransactional
public void createOrder(Order order) {
    orderRepository.save(order);
    // 其他操作
}

总结

  • 如果你用Java EE容器,优先选方案2(CMT),最省心;
  • 轻量容器下可以用方案1(JTA+第三方实现);
  • 简单场景或不想依赖JTA的话,用方案3(手动JDBC事务);
  • 想要声明式事务又不想用Spring,选方案4(AspectJ)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:21:58