#spring #spring-boot #docker #transactions #spring-transactions
#весна #пружинный ботинок #докер #операции #весна-сделки
Вопрос:
У меня есть простое приложение SpringBoot, которое использует SpringData и имеет следующую структуру SlotConfigsController -gt; Репозиторий (CrudRepository)
@RestController @RequiredArgsConstructor public class ConfigsController { private final ConfigsRepository configsRepository; @PostMapping(path = "/configs") public ResponseEntitylt;Voidgt; saveConfig(@RequestBody ConfigDto config) { ConfigEntity config = CONFIGS_MAPPER.dtoToEntity(config); configsRepository.save(config); log.info("Transactional method finished"); } }
Хранилище
@Repository public interface ConfigsRepository extends CrudRepositorylt;ConfigsEntity, Longgt; { @Transactional ConfigsEntity save(ConfigsEntity entity); }
Я запустил базу данных Postgres с помощью docker-compose и включил журналы через
environment: - EXTRA_CONF=log_statement=all
Что я заметил во время анализа журнала, так это то, что фактическая фиксация БД (внутри журнала docker) происходит после log.info(...)
вызова.
Вот журнал из кода
17:12:11,856 TRACE [http-nio-8080-exec-2] [TransactionSynchronizationManager.java] - Clearing transaction synchronization 17:12:11,856 TRACE [http-nio-8080-exec-2] [TransactionSynchronizationManager.java] - Removed value [org.springframework.jdbc.datasource.ConnectionHolder@550de51c] for key [HikariDataSource (Hikari)] from thread [http-nio-8080-exec-2] 17:12:11,856 TRACE [http-nio-8080-exec-2] [TransactionSynchronizationManager.java] - Removed value [org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$DefaultCrudMethodMetadata@6752dcc] for key [public abstract java.lang.Object org.springframework.data.repository.CrudRepository.save(java.lang.Object)] from thread [http-nio-8080-exec-2] 17:12:11,857 INFO [http-nio-8080-exec-2] [SlotConfigsController.java] - Transactional method finished 17:12:11,863 TRACE [http-nio-8080-exec-2] [TransactionSynchronizationManager.java] - Removed value [org.springframework.orm.jpa.EntityManagerHolder@4ecd9132] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean@2210e466] from thread [http-nio-8080-exec-2]
А вот журнал базы данных docker
17:12:11.871 UTC [555] test@test LOG: execute lt;unnamedgt;: update public.slot_configs set close_time=$1 where slot_config_id=$2 17:12:11.871 UTC [555] test@test DETAIL: parameters: $1 = '1630', $2 = 5 17:12:11.877 UTC [555] test@test LOG: execute S_2: COMMIT
В 17:12:11 857 мы вышли из транзакционного CrudRepository.save
метода, но реальная вставка данных в БД и фиксация транзакции происходят только в 17:12:11.871 — 17:12:11.877
Я предполагал, что, когда @Transactional
метод будет завершен, данные уже должны быть в БД, но, похоже, это действие асинхронно. Я также пытался создать службу между контроллером и репозиторием и пометить метод сохранения в службе как @Transactional(propagation = Propagation.REQUIRES_NEW)
, но это ничего не меняет. Все еще существует задержка между транзакциями кода и фактическими транзакциями в БД.
Почему это происходит? И можно ли сказать Spring, чтобы дождаться фиксации транзакции БД перед выходом из @Transactional
метода?
Комментарии:
1. Ваше понимание неверно. Транзакция будет зафиксирована после
@Transactional
ее завершения. Это ваша транзакционная граница. В основном происходит запуск транзакции -gt; gt; метод выполнения службы -gt; gt; фиксация транзакции . Нет фиксации где-то между вашими методами при вызове службы. Так что все работает так, как задумано. Таким образом, фиксация происходит после вызоваlog.info
.2. В контроллере нет никаких
@Transactional
аннотаций. Только метод сохранения помечен как@Transactional
. Итак, после завершенияsave
метода мы уже вышли из нашей транзакции, и мы перешли к следующей строке кодаlog.info
, позвольте мне отредактировать классы, чтобы это было более понятно.3. Также другое дело, что вы синхронизируетесь по меткам времени, если эти часы не совпадают, у вас все равно не будет соответствующей временной шкалы. Сопоставление/сопоставление журналов с метками времени проблематично, имхо (и опыт). Параметр
@Transactional
onsave
не добавляет ничего, чтоsave
уже делает метод по умолчанию. Наконец, отключите режим открытой сессии, так как это также может повлиять на ситуацию.4. @M. Deinum, спасибо, я добавил
@Transactional
метод сохранения только для ясности (я понимаю, что это ни на что не влияет). Что касается отключенной открытой сессии в поле зрения- спасибо! Я не знал об этом, проверяя сейчас. Кстати, в случае, если временные метки не рекомендуются, может быть, есть предложения с вашей стороны?5. Если есть хоть малейшее отклонение между часами или что-то в этом роде, ваша регистрация будет отключена. Вы хотите включить промежуток и т. Д. Что-то вроде того, что предоставляет OpenTrace/Zipkin.