无状态会话 EJB 3.0 中的事务回滚

发布于 2024-10-15 15:53:55 字数 3699 浏览 9 评论 0原文

我有一个符合 3.0 规范的无状态会话 EJB。

/*Remote Interface*/

package com.nseit.ncfm2.data.ejb;
import java.sql.SQLException;
import java.util.Collection;

import javax.ejb.Remote;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.naming.NamingException;

import com.nseit.ncfm2.security.Audit;

@Remote
public interface ProductionDataChangesRequestsRemote {

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public boolean shiftCandidateDetails(String sourceNcfmId,
            String destinationNcfmId, Collection<String> specialCasesList, String shiftingRemarks, String user, Audit updtAudit) throws NamingException, SQLException;
}


/*Bean Class*/

package com.nseit.ncfm2.data.ejb;

import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.naming.NamingException;

import com.nseit.ncfm2.security.Audit;
import com.nseit.ncfm2.util.server.lookup.LookUpServerResources;
import java.sql.*;
import java.util.*;

/**
 * Session Bean implementation class ProductionDataChangesRequestsBean
 */
@Stateless(name = "ProductionDataChangesRequestsBean", mappedName = "ProductionDataChangesRequestsEJB")
@Remote(ProductionDataChangesRequestsRemote.class)
@TransactionManagement(TransactionManagementType.CONTAINER)
public class ProductionDataChangesRequestsBean implements
        ProductionDataChangesRequestsRemote {

/**
 * Default constructor.
 */
public ProductionDataChangesRequestsBean() {
    // TODO Auto-generated constructor stub
}

@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public boolean shiftCandidateDetails(String sourceNcfmId,
        String destinationNcfmId, Collection<String> specialCasesList,
        String shiftingRemarks, String user, Audit updtAudit)
        throws NamingException, SQLException {
    // TODO Auto-generated method stub
    Connection conn = null;
    PreparedStatement pstmt = null;

    int updtCnt = 0;

    boolean areDetailsShifted = false;

    try {
        ..............
        ..............
        ..............

        /* Start: update table-1 */
        ..............
        ..............
        ..............

        updtCnt = pstmt.executeUpdate();
        ..............
        ..............
        ..............

        /* End: update table-1 */


        /* Start: update table-2 */
        ..............
        ..............
        ..............

        updtCnt = pstmt.executeUpdate();
        ..............
        ..............
        ..............

        /* End: update table-2 */

        areDetailsShifted = true;

    } /*catch (SQLException e) {
        // TODO Auto-generated catch block
        System.out
                .println("SQLException in ProductionDataChangesRequestsBean.shiftCandidateDetails(...) "
                        + e.getMessage());
        // e.printStackTrace();

        context.setRollbackOnly();

    } */finally {
        LookUpServerResources.closeStatement(pstmt);
        LookUpServerResources.closeConnection(conn);
    }

    return areDetailsShifted;
}

}

目前,如果第一个表更新成功并且第二个表更新出现异常,则不会发生回滚,即更新第一个表中的记录。

我希望在发生 SQLException 时回滚事务(或者就此而言,如果发生任何运行时异常)。

我尝试了两种方法:

  1. 在 SQLException 的 catch 块中使用 context.setRollbackOnly()
  2. 抛出 SQLException

在这两种情况下,事务都没有回滚。

我怎样才能实现这一点:

  1. 不使用 @ApplicationException 注释(因为我没有任何应用程序异常)
  2. 不捕获 SQLException 然后调用 context.setRollbackOnly()

或者什么是标准方法?

I have a stateless session EJB as per 3.0 spec.

/*Remote Interface*/

package com.nseit.ncfm2.data.ejb;
import java.sql.SQLException;
import java.util.Collection;

import javax.ejb.Remote;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.naming.NamingException;

import com.nseit.ncfm2.security.Audit;

@Remote
public interface ProductionDataChangesRequestsRemote {

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public boolean shiftCandidateDetails(String sourceNcfmId,
            String destinationNcfmId, Collection<String> specialCasesList, String shiftingRemarks, String user, Audit updtAudit) throws NamingException, SQLException;
}


/*Bean Class*/

package com.nseit.ncfm2.data.ejb;

import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.naming.NamingException;

import com.nseit.ncfm2.security.Audit;
import com.nseit.ncfm2.util.server.lookup.LookUpServerResources;
import java.sql.*;
import java.util.*;

/**
 * Session Bean implementation class ProductionDataChangesRequestsBean
 */
@Stateless(name = "ProductionDataChangesRequestsBean", mappedName = "ProductionDataChangesRequestsEJB")
@Remote(ProductionDataChangesRequestsRemote.class)
@TransactionManagement(TransactionManagementType.CONTAINER)
public class ProductionDataChangesRequestsBean implements
        ProductionDataChangesRequestsRemote {

/**
 * Default constructor.
 */
public ProductionDataChangesRequestsBean() {
    // TODO Auto-generated constructor stub
}

@Override
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public boolean shiftCandidateDetails(String sourceNcfmId,
        String destinationNcfmId, Collection<String> specialCasesList,
        String shiftingRemarks, String user, Audit updtAudit)
        throws NamingException, SQLException {
    // TODO Auto-generated method stub
    Connection conn = null;
    PreparedStatement pstmt = null;

    int updtCnt = 0;

    boolean areDetailsShifted = false;

    try {
        ..............
        ..............
        ..............

        /* Start: update table-1 */
        ..............
        ..............
        ..............

        updtCnt = pstmt.executeUpdate();
        ..............
        ..............
        ..............

        /* End: update table-1 */


        /* Start: update table-2 */
        ..............
        ..............
        ..............

        updtCnt = pstmt.executeUpdate();
        ..............
        ..............
        ..............

        /* End: update table-2 */

        areDetailsShifted = true;

    } /*catch (SQLException e) {
        // TODO Auto-generated catch block
        System.out
                .println("SQLException in ProductionDataChangesRequestsBean.shiftCandidateDetails(...) "
                        + e.getMessage());
        // e.printStackTrace();

        context.setRollbackOnly();

    } */finally {
        LookUpServerResources.closeStatement(pstmt);
        LookUpServerResources.closeConnection(conn);
    }

    return areDetailsShifted;
}

}

Currently, if the 1st table update succeeds and the 2nd table update gives an exception, a rollback is not taking place, i.e records in 1st table are updated.

I want the transaction to be rolled back in case an SQLException occurs (or for that matter, if any runtime exception occurs).

I tried two approaches :

  1. Use of context.setRollbackOnly() in catch block for SQLException
  2. Throwing the SQLException

In both the cases, the transaction didn't roll back.

How can I achieve this:

  1. Without the usage of @ApplicationException annotation (as I do not have any application exceptions)
  2. Without catching the SQLException and then calling context.setRollbackOnly()

Or what is the standard way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

葬花如无物 2024-10-22 15:53:55

你必须抛出RuntimeException

You will have to throw RuntimeException

匿名。 2024-10-22 15:53:55

标准方法是使用底层 JPA 来实现持久性,而不是使用 JDBC。
JPA 提供了一个标准的 OR 映射解决方案,该解决方案很好地集成到了符合 EJB 3.x 的容器中。

另外,从您的代码来看,它反映出您有 TransactionManagementType.CONTAINER ,但仍然手动管理事务。

在 Bean 管理的事务中
分界,会话中的代码
或显式消息驱动 bean
标记了边界
交易。虽然豆类与
容器管理的事务需要
编码较少,但它们有一个限制:
当一个方法正在执行时,它可以是
与单个相关联
交易或根本没有交易。
如果这个限制会使编码
你的豆子很难,你应该
考虑使用bean管理
交易。

The standard way is to use underlying JPA for persistence rather then using JDBC.
JPA provides a standard OR mapping solution that's well-integrated into an EJB 3.x-compliant container.

Also from your code it reflects that you have TransactionManagementType.CONTAINER , but still managing transaction manually.

In bean-managed transaction
demarcation, the code in the session
or message-driven bean explicitly
marks the boundaries of the
transaction. Although beans with
container-managed transactions require
less coding, they have one limitation:
When a method is executing, it can be
associated with either a single
transaction or no transaction at all.
If this limitation will make coding
your bean difficult, you should
consider using bean-managed
transactions.

合约呢 2024-10-22 15:53:55

看起来您正在 bean 中使用 JDBC API。我不认为容器管理那些 JDBC 事务。对于 CMT,您必须调用容器管理实体管理器上的操作才能使回滚按预期工作。

It looks like you are using JDBC API in your bean. I don't think container manages those JDBC transactions. For CMT, you'd have to invoke operations on a container managed entity manager for the rollback to work as expected.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文