tomee-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Svetlin Zarev (JIRA)" <>
Subject [jira] [Created] (TOMEE-2043) Thread local transactions are left open across requests
Date Thu, 01 Jun 2017 09:13:04 GMT
Svetlin Zarev created TOMEE-2043:

             Summary: Thread local transactions are left open across requests
                 Key: TOMEE-2043
             Project: TomEE
          Issue Type: Bug
          Components: TomEE Core Server
    Affects Versions: 7.0.3
            Reporter: Svetlin Zarev

@Transactional CDI bean methods annotated with     @Transactional(dontRollbackOn = SomeException.class)
do not commit the transaction at the end of the request/response cycle when the SomeException
exception is thrown. As a result the thread local transaction object is preserved across requests
which makes unrelated requests to fail with "Nested transactions are not supported".

Sample application that reproduces the issue is attached to the ticket.
Sample valve that can be used to demonstrate the issue: 

public final class LeakedTransactionDetectionValve extends ValveBase {
    private static final Logger logger = Logger.getLogger(LeakedTransactionDetectionValve.class.getName());

    public void invoke(Request request, Response response) throws IOException, ServletException
        boolean hasActiveTransaction = false;
        try {
            final Collection<Transaction> transactionsBeforeRequest = getTransactions();
            for (Transaction transaction : transactionsBeforeRequest) {
                if (transaction.getStatus() == Status.STATUS_ACTIVE) {
                    hasActiveTransaction = true;
        } catch (Exception ex) {

        getNext().invoke(request, response);

        if (!hasActiveTransaction) {
            try {
                final Collection<Transaction> transactionsAfterRequest = getTransactions();
                for (Transaction transaction : transactionsAfterRequest) {
                    if (transaction.getStatus() == Status.STATUS_ACTIVE) {
                        logger.log(Level.SEVERE, "Found active transaction: "
                                + request.getRequestURI()
                                + "?"
                                + request.getQueryString()
            } catch (Exception ex) {
                logger.log(Level.SEVERE, "Failed to determine thread local transaction status.",

    Collection<Transaction> getTransactions() throws NoSuchFieldException, IllegalAccessException
        final Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
        final Object threadLocals = threadLocalsField.get(Thread.currentThread());

        final Field tableField = threadLocals.getClass().getDeclaredField("table");
        final Object table = tableField.get(threadLocals);

        final Collection<Transaction> transactions = new LinkedList<>();
        for (int i = 0; i < Array.getLength(table); i++) {
            final Object entry = Array.get(table, i);
            if (null != entry) {
                final Field valueField = entry.getClass().getDeclaredField("value");

                final Object value = valueField.get(entry);
                if (value instanceof Transaction) {
                    transactions.add((Transaction) value);

        return transactions;

PS: in addition to the issue above, the org.apache.openejb.cdi.transactional.InterceptorBase
must not wrap the exception specified in the "donotRollbackOn" attribute inside TransactionalException

This message was sent by Atlassian JIRA

View raw message