Откат транзакции в сеансе без сохранения состояния EJB 3.0 - PullRequest
0 голосов
/ 03 февраля 2011

У меня EJB сеанса без сохранения состояния согласно спецификации 3.0.

/*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;
}

}

В настоящее время, если 1-е обновление таблицы завершается успешно, а 2-е обновление таблицы дает исключение, откат не выполняется, т.е. обновляются записи в 1-й таблице.

Я хочу, чтобы транзакция откатывалась в случае возникновения исключения SQLException (или, если на то пошло, в случае возникновения какого-либо исключения во время выполнения).

Я попробовал два подхода:

  1. Использование context.setRollbackOnly() в блоке catch для SQLException
  2. Бросив SQLException

В обоих случаях транзакция не откатилась.

Как мне этого добиться:

  1. Без использования аннотации @ApplicationException (поскольку у меня нет исключений для приложений)
  2. Не перехватывая исключение SQLE, а затем вызывая context.setRollbackOnly()

или какой стандартный способ?

Ответы [ 3 ]

3 голосов
/ 04 февраля 2011

Вам придется бросить RuntimeException

1 голос
/ 07 мая 2011

Стандартный способ - использовать базовый JPA для сохранения, а не использовать JDBC. JPA предоставляет стандартное решение OR mapping, которое хорошо интегрировано в EJB 3.x-совместимый контейнер.

Также из вашего кода видно, что у вас есть TransactionManagementType.CONTAINER, но вы по-прежнему управляете транзакцией вручную.

В демаркации транзакции, управляемой бином, код в сеансе или на основе сообщенийБин явно отмечает границы транзакции.Хотя бины с управляемыми контейнером транзакциями требуют меньшего количества кодирования, у них есть одно ограничение: когда метод выполняется, он может быть связан либо с одной транзакцией, либо вообще без транзакции.Если это ограничение затруднит кодирование вашего компонента, вам следует рассмотреть возможность использования транзакций, управляемых компонентом.

0 голосов
/ 15 февраля 2011

Похоже, вы используете JDBC API в своем бине. Я не думаю, что контейнер управляет этими транзакциями JDBC. Для CMT вам придется вызывать операции в диспетчере управляемых объектов контейнера, чтобы откат работал должным образом.

...