РЕДАКТИРОВАТЬ: Я пошел с решением arogos
, что лучше, потом.Я оставляю это здесь на тот случай, если кому-то понадобится сделать более эзотерическое обновление, в котором Hibernate не сможет его обрезать.
Хотя мне так и не удалось найти истинное решение, я нашел обходной путь в контексте весенней загрузки, который работает до тех пор, пока вам нужно или не против применить триггер также при обновлении.У этого есть много недостатков, которые вынудили меня в крайнем случае использовать триггеры во-первых, но по крайней мере это сводит к минимуму масштаб проблемы только для H2 и только для вставок, в проекте, который должен поддерживать две другие СУБД, где триггерподход работает просто отлично.
Я в основном создал триггер обновления, обработчик пост-вставки, который вызывает фиктивное обновление, если СУБД Н2, и комментарий, напоминающий, что каждая операция вставки, которая не исходит отЗапрос конечной точки REST должен вызывать обработчик вручную .Именно это поведение и стало причиной того, что я стал прибегать к триггерам, после того как попробовал JPA @PostInsert
и @PostUpdate
и получил ошибки, связанные с попытками чтения из таблицы, в которую вы только что написали - мое понимание этого заключалось в том, что есть чтениеблокировка, чтобы ваш @PostInsert
/ @PostUpdate
не мог читать из таблицы любым способом.
Триггер в моем src/main/resources/data-h2.sql
:
-- creating schema changes in data file because schema.sql overwrites JPA schema intialization
-- https://github.com/spring-projects/spring-boot/issues/9048
create trigger after_subtest_result_update after update on subtest_result
for each row call "com.siemens.mftool.dialects.H2SubtestResultTrigger";
Обработчик:
package com.siemens.mftool.entity.handlers;
import com.siemens.mftool.entity.SubtestResult;
import com.siemens.mftool.repositories.SubtestResultRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.rest.core.annotation.HandleAfterCreate;
import org.springframework.data.rest.core.annotation.RepositoryEventHandler;
import org.springframework.stereotype.Component;
/** workaround for H2 post insert triggers not working because of improperly
* handled generated keys
* must be called manually if the repo invocation does not come from a REST
* request
*/
@Component
@RepositoryEventHandler(SubtestResult.class)
public class H2WorkaroundSubtestResultHandler {
private final SubtestResultRepository subtestResultRepository;
@Value("${spring.datasource.platform}")
private String platform;
@Autowired
public H2WorkaroundSubtestResultHandler(SubtestResultRepository subtestResultRepository) {
this.subtestResultRepository = subtestResultRepository;
}
@HandleAfterCreate
public void handleAfterCreate(final SubtestResult subtestResult) {
if("h2".equals(platform)) {
subtestResultRepository.h2Workaround(subtestResult);
}
}
}
Метод репозитория:
// force an update to the newly inserted subtestResult so the
// after-update trigger is triggered
@Modifying
@Query(nativeQuery = true, value =
"update subtest_result " +
"set id = :#{ #subtestResult.id } " +
"where id = :#{ #subtestResult.id } ")
void h2Workaround(SubtestResult subtestResult);
Как выглядит вызов, когда выполняется программно:
h2WorkaroundSubtestResultHandler.handleAfterCreate(subtestResult);
Все еще болевая точка, но это, по меньшей мере, болевая точка, а не целая больлиния.