Интерес представляют следующие колонки: NUM_ROWS — текущее количество строк в таблице, AUTOINC — значение AUTO INCREMENT. Забегая вперёд отмечу, что NUM_ROWS в моей реализации также повела себя лениво (скорее всего на стороне СУБД имеется какая-то гонка и оно просто не успевает обновиться до того, как я делаю SELECT из этой таблицы после теста). А вот на AUTOINC, по разумным соображениям, должен существовать лок, обеспечивающий синхронизированный доступ. К тому же забавно, что после создания таблицы или вызова TRUNCATE на ней это значения сбрасывается в 0, а после вставки первой строки оно становится равным 2.
Упрощённо, алгоритм действий получился следующий:
- В базовом классе для тестов я определил метод с аннотацией @AfterAll, который делает всю работу.
- Метод сперва получает список всех таблиц в приложении. Это ленивая и однократная операция, т. к. набор таблиц не меняется во время тестирования. Запрос выполняется к таблице information_schema.TABLES, забираем в множество названия всех тех таблиц, которые лежат в тестовой схеме. Так мы их посчитали, а заодно слегка отфильтровали (убрали неинтересные DatabaseChangelog, DatabaseChangelogLock, ShedLock).
- Выполняется запрос в таблицу information_schema.INNODB_TABLESTATS, читаем только колонки NAME и AUTOINC, из результата выбираем только те, у которых AUTOINC больше нуля. Кроме того, фильтруем таблицы по схеме и имени.
- Каждой таблице из результирующего списка вызываем TRUNCATE. Это не только удаляет из неё все данные, но и сбрасывает AUTOINC обратно в ноль.
Теоретически, да и практически, с кодом всё в порядке — он рабочий. Только при первом же запуске появляется новая проблема:
Access denied; you need (at least one of) the PROCESS privilege(s) for this operation. Оказывается, что в Testcontainers при использовании базы данных через строку JDBC-подключения невозможно поменять имя пользователя. По крайней мере это справедливо для MySQL. При этом в запускаемом контейнере имеется два пользователя: root и test (по умолчанию), оба с паролем test (по умолчанию), и оба могут подключаться с любого хоста. Пользователь test не имеет никаких специальных прав, root, естественно, имеет их все. Поэтому пришлось отказаться от конфигурирования контейнера через jdbc-url и создать отдельную тестовую конфигурацию, которая будет поднимать контейнер при создании DataSource, и использовать учётную запись root/test: