Java EE - Есть ли какой-либо правильный способ получить идентификатор текущей транзакции JPA независимо от сервера приложений - PullRequest
0 голосов
/ 09 июля 2020

В настоящее время мне нужно манипулировать некоторым кодом c EclipseLink из самой библиотеки EclipseLink. Столкнулся с неприятной проблемой, когда мне нужно увеличить уровень трассировки на уровне параллелизма EclipseLink.

Один фрагмент метаданных, который я хочу получить для моей трассировки, - это идентификатор текущей транзакции JTA.

Поскольку мои изменения кода происходят в середине диспетчера параллелизма EclipseLink, я на самом деле очень ограничен в плане активного контекста выполнения. Мне доступно очень мало контекста, определенно, в тот момент, когда я добавляю трассировку, в моих руках нет диспетчера сущностей.

К счастью, в приложениях JEE у вас есть мощный уровень JNDI для доступа в любой момент на момент времени.

Вопрос прост: существует ли какое-либо официальное имя поиска JEE JNDI, которое официально допустимо для получения идентификатора текущей транзакции JTA?

В приложении Java EE, если вы внутри для вставляемого контекста CDI вы можете сделать что-то вроде:

 @Resource
    transient TransactionSynchronizationRegistry tsr;

И оттуда вы получите этот неприятный метод: tsr.getTransactionKey ()

Но объект, который выходит из него обычно имеет TO_STRING, который изменяется в зависимости от статуса транзакции.

Вот пример oracle.

Name = [EJB фасад.systemtest.ReproduceBugFacadeImpl.reproduceBugThreadThatReadsEntityD ()], Xid = BEA1-035D63C7D4B318977989 (1127385808), Статус = Откат. [Reason = weblogi c .transaction.internal.TimedOutException: время ожидания транзакции истекло через 61 секунду BEA1-035D63C7D4B318977989], numRepliesOwedMe = 0, numRepliesOwedOthers = 0, секунды с момента begin = 2311, activeSecread = -2180, использовать = Поток [[STUCK] ExecuteThread: '12' для очереди: 'weblogi c .kernel.Default (самонастройка)', 1, объединенные потоки], XAServerResourceInfo [DS_Maint-3568-eclipsedeadlock_oracledb] = (ServerResourceInfo [DS_Maint- 3568-eclipsedeadlock_oracledb] = (состояние = откат, назначено = AdminServer), xar = DS, повторно зарегистрировано = false), SCInfo [Maint-3568-eclipsedeadlock_oracledb + AdminServer] = (состояние = откат), свойства = ({weblogi c .transaction.partitionName = ДОМЕН, веб-журналы c .transaction.name = [EJB фасад.systemtest.ReproduceBugFacadeImpl.reproduceBugThreadThatReadsEntityD ()]}), локальные свойства = ({веб-журналы c .jdta c .jdta = [XAConnection не привязан к этому TxInfo]}), OwnerTransactionManager = ServerTM [ServerCoordinatorDescriptor = (CoordinatorURL = AdminServer + 10.41.144.234: 70 01 + Мейнт-3568-eclipsedeadlock_oracledb + T3 + CoordinatorNonSecureURL = AdminServer + 10.41.144.234: 7001Maint-3568-eclipsedeadlock_oracledb + T3 + coordinatorSecureURL = AdminServer + 10.41.144.234: 7002 + Мейнт-3568-eclipsedeadlock_oracledb + T3S + XAResources = {WLStore_Maint-3568-eclipsedeadlock_oracledb__WLS_AdminServer , DS_Maint-3568-eclipsedeadlock_oracledb, WSATGatewayRM_AdminServer_Maint-3568-eclipsedeadlock_oracledb}, NonXAResources = {})], CoordinatorURL = AdminServer + 10.41.144.234: 7001 + Maintsedeadlock * + 10.41.144.234: 7001 + Maintse-23 * tdlock

tclip-1021 * tclip *1022* tclip * + 1021 * tcl_3 * 8 * tcl_23 * + 1 * tcl_23 * + * tcl_23 * + * tcl_23 * + * tcl_23 * + * tcl_23 * + * tcl_23 * + 1 моя точка останова отладки, чтобы получить идентификатор транзакции, который мне нужен: (извините, что код выглядит так отвратительно, но eclipse не допускает выражения строки muti)
(( (new javax.naming.InitialContext()).lookup("java:comp/TransactionSynchronizationRegistry")).getClass().getMethod("getTransactionKey")).invoke(( (new javax.naming.InitialContext()).lookup("java:comp/TransactionSynchronizationRegistry"))).getClass().getMethod("getXid").invoke(    (( (new javax.naming.InitialContext()).lookup("java:comp/TransactionSynchronizationRegistry")).getClass().getMethod("getTransactionKey")).invoke( (new javax.naming.InitialContext()).lookup("java:comp/TransactionSynchronizationRegistry"))   )

И это дает мне именно то, что я хочу:

BEA1-035D63C7D4B318977989

Нет лучшего способа java some basi c JNDI до тех пор, пока не появится вспомогательный класс, который придет с идентификатором транзакции должным образом независимо ?

Для меня эта информация абсолютно критично ... Тип отслеживания, который я добавляю к уровню параллелизма EclipseLink, должен точно знать, в какой транзакции JPA был выпущен или сброшен определенный ключ кеша c. Без этого я не могу определить конкретную ошибку.

Следующее - то же самое, что и приведенные выше однострочные выражения, но их легче читать. Должен быть способ сделать это лучше:

 /**
     * Reflection method for {@code javax.transaction.TransactionSynchronizationRegistry.getTransactionKey()}
     *
     * The transaction object key in weblogic has a to string of the form
     * {@code Name=[EJB facade.systemtest.ReproduceBugFacadeImpl.reproduceBugThreadThatReadsEntityD()],Xid=BEA1-035D63C7D4B318977989(1127385808),Status=Rolled back. [Reason=weblogic.transaction.internal.TimedOutException: Transaction timed out after 61 seconds
     * BEA1-035D63C7D4B318977989],numRepliesOwedMe=0,numRepliesOwedOthers=0,seconds since begin=1230,seconds
     * left=-1099,useSecure=false,activeThread=Thread[[STUCK] ExecuteThread: '12' for queue: 'weblogic.kernel.Default
     * (self-tuning)',1,Pooled
     * Threads],XAServerResourceInfo[_DS_Maint-3568-eclipsedeadlock_oracledb]=(ServerResourceInfo[_DS_Maint-3568-eclipsedeadlock_oracledb]=(state=rolledback,assigned=AdminServer),xar=_DS,re-Registered
     * =
     * false),SCInfo[Maint-3568-eclipsedeadlock_oracledb+AdminServer]=(state=rolledback),properties=({weblogic.transaction.partitionName=DOMAIN,
     * weblogic.transaction.name=[EJB
     * facade.systemtest.ReproduceBugFacadeImpl.reproduceBugThreadThatReadsEntityD()]}),local
     * properties=({weblogic.jdbc.jta._DS=[ No XAConnection is attached to this TxInfo
     * ]}),OwnerTransactionManager=ServerTM[ServerCoordinatorDescriptor=(CoordinatorURL=AdminServer+10.41.144.234:7001+Maint-3568-eclipsedeadlock_oracledb+t3+
     * CoordinatorNonSecureURL=AdminServer+10.41.144.234:7001+Maint-3568-eclipsedeadlock_oracledb+t3+
     * coordinatorSecureURL=AdminServer+10.41.144.234:7002+Maint-3568-eclipsedeadlock_oracledb+t3s+,
     * XAResources={WLStore_Maint-3568-eclipsedeadlock_oracledb__WLS_AdminServer,
     * _DS_Maint-3568-eclipsedeadlock_oracledb,
     * WSATGatewayRM_AdminServer_Maint-3568-eclipsedeadlock_oracledb},NonXAResources={})],CoordinatorURL=AdminServer+10.41.144.234:7001+Maint-3568-eclipsedeadlock_oracledb+t3+)
     * }
     */
    private static Method TRANSACTION_SYNCH_REGISTRY_TRANSACT_KEY_METHOD = null;

    /**
     * Reflection method for {@code javax.transaction.TransactionSynchronizationRegistry.getTransactionKey().getXid()}
     *
     * Which is  a method that returns a transaction id of the from: {@code BEA1-035D63C7D4B318977989}
     */
    private static Method WEBGLOCIC_TRANSACTION_XID_METHOD = null;


    /**
     *
     * @return A DTo that can tells us the app server transaction ID on which eclipselink is currently working. This is
     *         additional metadata we can add when we are acquiring for example a read lock.
     */
    public HackingEclipseCurrentJtaTransactionInfoDto createHackingEclipseCurrentJtaTransactionInfoDto() {
        try {
            InitialContext jndi = new InitialContext();

            // (a) Load the method methodGetTransactionKey getTransactionKey
            Method methodGetTransactionKey = getTransactionSynchronizationRegistryGetTransactionKeyMethod();

            // (b) load the javax.transaction.TransactionSynchronizationRegistry
            Object transactionSynchronizationRegistry = jndi.lookup("java:comp/TransactionSynchronizationRegistry");

            // (c) execute the getTransactionKey on the TransactionSynchronizationRegistry
            Object transactionSynchronizationRegistryTransactionKey = methodGetTransactionKey
                    .invoke(transactionSynchronizationRegistry);

            // (d) Get the method to get the weblogic transaction ids
            // currently we only support weblogic
            Method weblogicGetXid = getWeblogicBEATransactionId(transactionSynchronizationRegistryTransactionKey);
            Object jpaTranasctionId = "actualTransactionIdNotSupportedForCurrentAppServer";
            if (weblogicGetXid != null) {
                jpaTranasctionId = weblogicGetXid.invoke(transactionSynchronizationRegistryTransactionKey);
            }

            // (e) If we reached this point we can now bbuild our DTO with the to strings from the two objects we care
            // abou
            return new HackingEclipseCurrentJtaTransactionInfoDto(
                    transactionSynchronizationRegistryTransactionKey.toString(), jpaTranasctionId.toString());

        } catch (Exception e) {
            final String dummyId = "createHackingEclipseCurrentJtaTransactionInfoDto_problems_doing_jndi_lookup";
            return new HackingEclipseCurrentJtaTransactionInfoDto(dummyId, dummyId);
        }
    }

    /**
     * @return the cached reflection method to get the Method
     *         {@code javax.transaction.TransactionSynchronizationRegistry.getTransactionKey()}
     */
    public static synchronized Method getTransactionSynchronizationRegistryGetTransactionKeyMethod() {
        try {
            if (TRANSACTION_SYNCH_REGISTRY_TRANSACT_KEY_METHOD == null) {
                InitialContext jndi = new InitialContext();
                Object transactionSynchronizationRegistry = jndi.lookup("java:comp/TransactionSynchronizationRegistry");
                TRANSACTION_SYNCH_REGISTRY_TRANSACT_KEY_METHOD = transactionSynchronizationRegistry.getClass()
                        .getMethod("getTransactionKey");
            }
            return TRANSACTION_SYNCH_REGISTRY_TRANSACT_KEY_METHOD;
        } catch (Exception unexpectedError) {
            throw new RuntimeException("getTransactionSynchronizationRegistryGetTransactionKeyMethod blew up",
                    unexpectedError);
        }

    }
    /**
     *
     * @param transactionKeyObject
     *  this the java object that comes out of doing  {@code javax.transaction.TransactionSynchronizationRegistry.getTransactionKey()}
     * @return The weblogic transaction key object is an object that contains a metod getXid which we want to load
     */
    public static synchronized Method getWeblogicBEATransactionId(Object transactionKeyObject) {
        if (WEBGLOCIC_TRANSACTION_XID_METHOD == null) {
            if (transactionKeyObject == null) {
                return null;
            }

            // In weblogic the transaction key object is an instanc eof
            // weblogic.transaction.internal.ServerTransactionImpl
            boolean isAppServerWelogic = transactionKeyObject.getClass().getCanonicalName().contains("weblogic");
            if (!isAppServerWelogic) {
                return null;
            }

            // In weblogic the class weblogic.transaction.internal.ServerTransactionImpl
            // has a very useful method getXid that returns BEA1-035D63C7D4B318977989
            try {
                WEBGLOCIC_TRANSACTION_XID_METHOD = transactionKeyObject.getClass().getMethod("getXid");
            } catch (Exception unexpectedError) {
                throw new RuntimeException("getWeblogicBEATransactionId blew up", unexpectedError);
            }
        }
        return WEBGLOCIC_TRANSACTION_XID_METHOD;
    }
...