Возникли проблемы с получением управляемых приложением транзакций для работы в JPA и WebSphere. - PullRequest
0 голосов
/ 18 января 2019

Я впервые использую JPA в среде WebSphere Commerce 7. Я смог заставить все это работать нормально, используя управляемое контейнером постоянство, и поэтому он сохраняет объекты по собственному желанию. Проблема заключается в том, что мне нужно убедиться, что данные сохраняются в БД до конца логики, в которой существует транзакция, потому что в конце имеется больше логики, которая может ввести условие гонки, если данные не переданы в База данных перед рукой. Если я добавлю точки отладки в точку, которую я вызываю entityManager.persist, а также после точки, которую я вызываю entityManager.close, я могу запросить базу данных и пока не вижу никаких данных. Но затем данные показывают, как только я позволил логике пройти свой курс и дойти до конца класса.

Итак, я решил, что мне нужно попробовать управляемость приложения. Когда я читаю о том, как это сделать, я очень запутался, потому что похоже, что я уже непреднамеренно структурировал свою логику, и все же он не позволяет мне управлять транзакцией. А также все, что я пробую, приводит к некоторому исключению, особенно когда я пытаюсь вызвать getTransaction.commit() или что-то в этом роде, чтобы зафиксировать вручную. Итак, вот что у меня было, что работало с использованием CMT (или, по крайней мере, я думаю, что это была CMT)

persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
    <persistence-unit name="NIJAVA" transaction-type="JTA">
        <jta-data-source>jdbc/com/ni/jndi</jta-data-source>
        <class>com.ni.commerce.nios.order.objects.NiPnAttributes</class>
        <class>com.ni.commerce.nios.order.objects.NiosAddresses</class>
        <class>com.ni.commerce.nios.order.objects.NiosContacts</class>
        <class>com.ni.commerce.nios.order.objects.NiosHeaders</class>
        <class>com.ni.commerce.nios.order.objects.NiosLines</class>
        <class>com.ni.commerce.nios.order.objects.NiosPayment</class>
        <exclude-unlisted-classes>true</exclude-unlisted-classes>
    </persistence-unit>
    </persistence>

Затем я создал JpaConnectionHelper, который я надеялся превратить в нечто, которому я мог бы передать значение, и сделать так, чтобы оно создавало для меня определенную единицу персистентности на основе строки, которую я передаю. Именно из-за этого я, кажется, являюсь выполнение логики, которая, по-видимому, уже является типом логики, необходимой для транзакций, управляемых приложением. Чтобы сделать эту работу, мне нужно вызвать Persistence.createEntityManagerFactory(persistenceUnitName), чтобы создать An EntityManagerFactory, так как я передаю в класс persistenceUnitName. И материал, который я прочитал, говорит мне, что это означает, что я собираюсь заниматься управлением приложениями - но, возможно, я ошибаюсь в этом. В любом случае, ядро ​​этого класса таково:

public class JpaConnectionHelper {
private EntityManagerFactory emFactory;
private EntityManager entityManager;

private void createEntityManager(String persistenceUnitName) throws ECException {
    setEmFactory(Persistence.createEntityManagerFactory(persistenceUnitName));
    setEntityManager(getEmFactory().createEntityManager());
  }

public EntityManager getEntityManager() {
    return entityManager;
  }
}

Получатель дает мне доступ к Entitymanager всякий раз, когда я передаю этот объект другим классам - возможно, это моя ошибка, когда я пытаюсь создать этот вспомогательный класс, а не просто создать логику постоянства ближе к тому месту, где я храню данные?

Затем я приступаю к созданию группы DAO, которые возвращают объект, который имеет все аннотации постоянства для сопоставления с моей базой данных. Я передаю экземпляр JpaConnectionHelper каждому DAO, так что теперь у них всех есть доступ к EntityManager и объектам, которые нужно сохранить. Я также даю всем DAO метод .persistDao(), который будет использовать EntityManager для вызова .persist() для созданных объектов.

Так что теперь у меня есть DAO с заполненным объектом, который я хочу сохранить, и EntityManager. Поэтому я вызываю постоянный метод в DAO, и он отлично сохраняет.

Вот как все это выглядит в действии от вызывающего класса:

// creates the EntityManager instance
JPAConnectionHelper jpaConnectionHelper = new JPAConnectionHelper();
// creates the object I want to save to the DB
NiosHeadersDao niosHeadersDao = zwebDaoFactory.getNiosHeadersDao(jpaConnectionHelper);
// this method is simply calling EntityManager.persist(niosHeaders);
niosHeadersDao.persistNiosHeaders();
// close EntityManager (if I try to close the factory it throws exception btw)
zwebDaoFactory.endConnectionScope(jpaConnectionHelper);

Итак, я хочу попробовать это сделать с помощью управляемых приложением транзакций. Я начинаю с того, что просто пытаюсь вызвать entityManager.flush() после вызова метода persist, но это ничего не делает (также не исключение). Затем я пытаюсь добавить entityManager.getTransaction.commit() в том же месте, и это выдает исключение, как вы могли ожидать:

You cannot access the EntityTransaction when using managed transactions.

Теперь поправьте меня, если я ошибаюсь, но разве это не означает, что я использую CMT? И если да, то почему я могу, если я не использую инъекции для EntityManagerFactory или Entitymanager? Кстати, я пробовал версии этого с и без первого звонка joinTransaction()

Итак, я перечитал больше и обнаружил, что мне может понадобиться ввести транзакцию UserTransaction, поэтому я пытаюсь добавить ее в JPAConnectionHelper (где находится экземпляр EntityManager)

@Resource
private UserTransaction userTransaction;

Но это всегда приводит к нулевой пользовательской транзакции. Я даже пытался создать его из InitialContext, вызывая .lookup(), но там не было UserTransaction, насколько я видел. Я попробовал эти попытки:

InitialContext ctx = new InitialContext();
UserTransaction tx = (UserTransaction) ctx.lookup("javax.transaction.UserTransaction");
UserTransaction tx = (UserTransaction) ctx.lookup("java:comp/UserTransaction");

Это привело к исключениям NamingException для каждого (не смейтесь, этот материал для вас тоже был новым ...)

Так что я даже не могу получить UserTransaction с beginTransaction() или commit().

В качестве теста я также пытался использовать инъекцию, чтобы получить объекты EntityManagerFactory и / или EntityManager, но все они также оказались нулевыми. Так что я делаю что-то настолько неправильное, что эти попытки инъекции ни к чему не привели.

Кто-нибудь может мне помочь? Спасибо, если вы сделали это так далеко ...

1 Ответ

0 голосов
/ 18 января 2019

Я нашел решение, которое дало мне доступ к транзакции, в частности, в среде WebSphere, используя:

TransactionManager.commit();

Кажется, что этот метод может получить доступ к контексту UserTransaction способом, который я не пробовал. Так что я уверен, что мог бы сделать это и сейчас, если нужно, но эй, если этот класс делает это для меня, почему бы просто не использовать это

...