EJB: Достижение распространения транзакции через транзакцию, управляемую компонентом?

У меня есть требование попытаться добиться распространения транзакций между несколькими компонентами с отслеживанием состояния. У меня есть 3 EJB с отслеживанием состояния в моем приложении. Начальная и конечная транзакция управляется внешним Java-приложением посредством вызова метода удаленного интерфейса.

@Remote
@Stateful
public class MyEJB1 implements RemoteEJB1{
@EJB
 private RemoteEJB2 ejb2;
@Resource
UserTransaction utx;

public void startTransaction() {
    try {

        utx.begin();

    } catch (NotSupportedException e) {
        throw new EJBException(e);
    } catch (SystemException e) {
        throw new EJBException(e);
    }
}

public void commitTransaction() {
    try {
        utx.commit();

    } catch (SecurityException e) {
        throw new EJBException(e);
    } catch (IllegalStateException e) {
        throw new EJBException(e);
    } catch (RollbackException e) {
        throw new EJBException(e);
    } catch (HeuristicMixedException e) {
        throw new EJBException(e);
    } catch (HeuristicRollbackException e) {
        throw new EJBException(e);
    } catch (SystemException e) {
        throw new EJBException(e);
    }
}

public RemoteEJB2 getEJB2() {
    return ejb2;
}

}


public class MyEJB2 implements RemoteEJB2{

@EJB
private RemoteEJB3 ejb3;
@Resource(name = "java:jboss/datasources/MyDS")
private DataSource ds;

public RemoteEJB3 getEJB3() {
    return ejb3;
}

@TransactionAttribute(TransactionAttributeType.MANDATORY)
public void insertElement(String elementName) {
    PreparedStatement pStat = null;
    Connection con = null;
    try {
        con = ds.getConnection();
        String sql = "insert into TRANSACTIONTEST(COL1,COL2) values(?,?)";
        pStat = con.prepareStatement(sql);
        pStat.setString(1, elementName);
        pStat.setDouble(2, Math.random());
        pStat.executeUpdate();

    } catch (Exception ex) {
        ex.printStackTrace();
    } finally {
        try {
            con.close();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}
}

public class MyEJB3 implements RemoteEJB3{
@Resource(name="java:jboss/datasources/MyDS")
private DataSource ds;

@TransactionAttribute(TransactionAttributeType.MANDATORY)
public void updateElement(String newName) {
    PreparedStatement pStat = null;
    Connection con = null;
    try{    con = getDs().getConnection();
        String sql ="update  TRANSACTIONTEST set COL1=?";           
        pStat = con.prepareStatement(sql);
        pStat.setString(1, newName);        
        pStat.executeUpdate();

    }catch(Exception ex){
        ex.printStackTrace();
    }finally{
        try {
            con.close();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}
}

Тестовый класс:

public class MyTest{
public static void main(String[] args) throws Exception {
    final Hashtable jndiProperties = new Hashtable();
    jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
    final Context context = new InitialContext(jndiProperties);
    MyEJB1 ejb1 = context.lookup("ejb:/EJBTrials/MyEJB1!edu.in.ejbinterfaces. RemoteEJB1?stateful");

    ejb1.startTransaction();
    RemoteEJB2 ejb2 = ejb1.getEJB2();
    ejb2.insertElement (“Test”);
    RemoteEJB3 ejb3 = ejb2.getEJB3();
    ejb3.updateElement (“UpdatedTest”);
    ejb1.commitTransaction();
}
}

В идеале я хотел бы, чтобы вся транзакция (вставки записей в db) была завершена после вызова commitTransaction() в bean-компоненте RemoteEJB1.

Я попробовал комбинацию BMT для EJB1 и CMT для EJB2 и EJB3, что привело к возникновению EJBTransactionRequiredException. Я попытался сделать все bean-компоненты как BMT. Однако согласно спецификации EJB3.1 BMT не может распространяться на несколько компонентов. Не могли бы вы сообщить мне о каких-либо идеях/ссылках, которые я мог бы использовать для решения этой проблемы?

Эталонный сервер приложений: JBOSS AS 7.1


person Pramod Kumar    schedule 28.10.2013    source источник
comment
Как сервер должен связать ejb1 с ejb2 экземплярами? Да, у них один и тот же аутентифицированный пользователь, но, насколько сервер знает, они могут вызываться из совершенно разных, не связанных между собой программ. Вам нужно будет вызывать методы ejb2 и ejb3 через ejb1.   -  person SJuan76    schedule 28.10.2013
comment
EJB1,EJB2,EJB3 представляют интерфейсы и объекты стандартной спецификации API. Следовательно, контракт на методы связан, и у меня нет свободы действий с точки зрения изменений. Одним из основных требований спецификации API является возможность реализации модели и интерфейса для поддержки транзакций, а управление транзакциями будет возложено на конечного пользователя моего вывода.   -  person Pramod Kumar    schedule 28.10.2013
comment
Я знаю это. Вопрос в том, что сервер не знает ни вашего кода, ни другого способа узнать, что разные bean-компоненты логически связаны, поэтому он не знает, являются ли они частью одной и той же транзакции или нет. Вы можете управлять транзакцией внутри EJB с отслеживанием состояния, потому что тогда сервер знает, что методы связаны (поскольку вы используете один и тот же EJB).   -  person SJuan76    schedule 28.10.2013


Ответы (1)


Не могли бы вы сообщить мне о каких-либо идеях/ссылках, которые я мог бы использовать для решения этой проблемы?

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

person Gabriel Aramburu    schedule 28.10.2013