Как обнаружить и откатить забытую программную транзакцию - PullRequest
0 голосов
/ 29 января 2019

Я работаю над веб-приложением, основанным на пружинном (spring-boot 1.5.13.RELEASE) подключении к базе данных MySQL 8.Мы решили работать с пулом tomcat jdbc (пул по умолчанию для весенней загрузки).Производственный отдел просит нас поработать над решением, чтобы избежать незавершенных транзакций с использованием свойства rollback-on-return (мы также установили auto-commit=false).

Мы не можем просто использовать транзакции, ориентированные на аннотации.Мы должны управлять некоторыми из них программно.Поэтому мы подумали, что использование rollback-on-return позволит избежать «отложенных» транзакций.К сожалению, во время фазы тестирования мы обнаруживаем, что если запрос создает «ожидающую транзакцию», то конец запроса не возвращается с возвращением соединения.И поэтому отката нет!

Я уже проверяю, закрыто ли соединение в нормальном случае, и так оно и есть.

Вот мой пример кода:

    public CommandLineRunner commandLineRunner(CustomerManager customerManager, EngineManager engineManager, DataSource dataSource) {
        return (String... args) -> {
            log.info("Start commandLineRunner" + engineManager.getTransactionPartEngineInnodbStatus());

            Thread t = new Thread(() -> {
                try {
                    customerManager.processII_notcomplete();
                } catch (Exception e) {
                    System.err.println(e.getMessage());
                }
            });

            t.start();
            t.join();

            log.info("End commandLineRunner" + engineManager.getTransactionPartEngineInnodbStatus());
        };
    }
    public void processII_notcomplete() {
        TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRED));

        log.info("processII [START]");

        Customer customer = customerRepository.findOne(1L);
        customer.lastName = "De " + customer.lastName;
        customerRepository.save(customer);
        log.info("processII: customerRepository.save(customer)" + engineManager.getTransactionPartEngineInnodbStatus() + "\n");

        // Intentionally don't commit the transaction to create the use case

        log.info("processII [END]");
    }

Я нашел JdbcInterceptor для регистрации заимствования и возврата соединения:

public class JDBCLogInterceptor extends JdbcInterceptor {

    private static final Logger log = LoggerFactory.getLogger(JDBCLogInterceptor.class);

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (log.isDebugEnabled()) {
            String name = method.getName();
            if (CLOSE_VAL.equals(name)) {
                log.debug(String.format("Returning Connection to Pool [%s]", proxy));
            }
        }
        return super.invoke(proxy, method, args);
    }

    @Override
    public void reset(ConnectionPool connPool, PooledConnection conn) {
        if (connPool != null && conn != null) {
            if (log.isDebugEnabled()) {
                log.debug(String.format("Getting Connection [%s], Pool active=[%s], idle=[%s]", conn.toString(),
                        connPool.getActive(), connPool.getIdle()));
            }
        }
    }

    @Override
    public void disconnected(ConnectionPool connPool, PooledConnection conn, boolean finalizing) {
        if (connPool != null && conn != null) {
            if (log.isDebugEnabled()) {
                log.debug(String.format("Closing Connection [%s], Pool active=[%s], idle=[%s]", conn.toString(),
                        connPool.getActive(), connPool.getIdle()));
            }
        }
    }
}

А вот соответствующая часть журнала:

ERROR 2019/01/29 16:28:13.975 - no-request --- mova.jpatest.JPATestConfig               - Start commandLineRunner
------------
TRANSACTIONS
------------
Trx id counter 269691
Purge done for trx's n:o < 269691 undo n:o < 0 state: running but idle
History list length 7
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 283703119152960, not started
0 lock struct(s), heap size 1136, 0 row lock(s) - [no-one]
DEBUG 2019/01/29 16:28:13.985 - no-request --- mova.jpatest.jdbc.JDBCLogInterceptor     - Getting Connection [PooledConnection[com.p6spy.engine.wrapper.ConnectionWrapper@63bf9fce]], Pool active=[1], idle=[9] - [no-one]
 INFO 2019/01/29 16:28:13.989 - no-request --- mova.jpatest.manager.CustomerManager     - processII [START] - [no-one]
 INFO 2019/01/29 16:28:13.995 - no-request --- p6spy                                    - statement --- select customer0_.id as id1_0_0_, customer0_.first_name as first_na2_0_0_, customer0_.last_name as last_nam3_0_0_ from customer customer0_ where customer0_.id=? - select customer0_.id as id1_0_0_, customer0_.first_name as first_na2_0_0_, customer0_.last_name as last_nam3_0_0_ from customer customer0_ where customer0_.id=1 - 01-29-19 16:28:13:995-2 [connection 8] - [no-one]
 INFO 2019/01/29 16:28:14.029 - no-request --- p6spy                                    - statement --- update customer set first_name=?, last_name=? where id=? - update customer set first_name='Jack', last_name='De De De De De De De Bauer' where id=1 - 01-29-19 16:28:14:29-0 [connection 8] - [no-one]
 INFO 2019/01/29 16:28:14.039 - no-request --- p6spy                                    - statement --- show engine innodb status; - show engine innodb status; - 01-29-19 16:28:14:39-6 [connection 8] - [no-one]
 INFO 2019/01/29 16:28:14.039 - no-request --- mova.jpatest.manager.CustomerManager     - processII: customerRepository.save(customer)
------------
TRANSACTIONS
------------
Trx id counter 269692
Purge done for trx's n:o < 269691 undo n:o < 0 state: running but idle
History list length 7
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 269691, ACTIVE 0 sec
2 lock struct(s), heap size 1136, 1 row lock(s), undo log entries 1
MySQL thread id 624, OS thread handle 20236, query id 47274 localhost 127.0.0.1 mohicane starting
show engine innodb status
Trx read view will not see trx with id >= 269691, sees < 269691
 - [no-one]
 INFO 2019/01/29 16:28:14.039 - no-request --- mova.jpatest.manager.CustomerManager     - processII [END] - [no-one]
DEBUG 2019/01/29 16:28:14.039 - no-request --- mova.jpatest.jdbc.JDBCLogInterceptor     - Getting Connection [PooledConnection[com.p6spy.engine.wrapper.ConnectionWrapper@3d646e1a]], Pool active=[2], idle=[8] - [no-one]
 INFO 2019/01/29 16:28:14.045 - no-request --- p6spy                                    - statement --- show engine innodb status; - show engine innodb status; - 01-29-19 16:28:14:45-2 [connection 9] - [no-one]
DEBUG 2019/01/29 16:28:14.045 - no-request --- mova.jpatest.jdbc.JDBCLogInterceptor     - Returning Connection to Pool [ProxyConnection[PooledConnection[com.p6spy.engine.wrapper.ConnectionWrapper@3d646e1a]]] - [no-one]
ERROR 2019/01/29 16:28:14.045 - no-request --- mova.jpatest.JPATestConfig               - End commandLineRunner
------------
TRANSACTIONS
------------
Trx id counter 269692
Purge done for trx's n:o < 269691 undo n:o < 0 state: running but idle
History list length 7
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 283703119153840, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 269691, ACTIVE 0 sec
2 lock struct(s), heap size 1136, 1 row lock(s), undo log entries 1
MySQL thread id 624, OS thread handle 20236, query id 47274 localhost 127.0.0.1 mohicane
Trx read view will not see trx with id >= 269691, sees < 269691 - [no-one]

Мои вопросы:

  • Есть ли способ убедиться, что ожидающая транзакция всегда будет завершена, как мы ожидали с откатом по возврату?
  • Можетмы обнаруживаем и возвращаем «невозвращенное» соединение в этом случае?
  • Кажется странным, что такое свойство существует и не управляется в этом случае?Зачем нам использовать откат после транзакции, которую мы уже зафиксировали или откат?Есть что-то, чего я не понимаю (конечно, это: p)?

NB: Пожалуйста, не обращайте внимания на уровень журнала ОШИБКИ, яЯ немного дальтоник.

Редактировать: Я пытаюсь через перехватчик, чтобы обнаружить текущую активную транзакцию, используя TransactionSynchronizationManager.isActualTransactionActive().Таким образом, я нахожу незаконченные, но когда я пытаюсь получить его с TransactionAspectSupport.currentTransactionStatus(), он возвращает мне null ???Не могу понять ...

Упрощение: Есть ли способ обнаружить и откатить забытую программную транзакцию (как показано в коде ниже)?

...