Мне нужно убедиться, что вставки фиксируются во время выполнения хранимой процедуры. При использовании Spring Boot Starter Data JPA 1.5 это было поведение по умолчанию для JpaTransactionManager
. В Spring Boot 2.x вставки не фиксируются, пока хранимая процедура не завершит выполнение.
Таким образом, вызов этой хранимой процедуры с использованием MGMT транзакции Spring Boot 2.x не будет вставлен через 1 минуту:
CREATE procedure [dbo].[test_insert]
as
begin
insert into myTempTable(col1)
values ("1");
WAITFOR DELAY '00:01';
end
GO
Но вызов ее с использованием MGMT транзакции Spring Boot 1.5 вставит немедленно что мне и нужно.
Вот код. Менеджер транзакций:
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
Репо:
public interface TestRepository extends Repository<String, Long> {
@Procedure("test_insert")
void testInsert();
}
Контрольный пример:
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional(transactionManager="transactionManager")
public class InsertRepositoryTest {
@Autowired
private TestRepository testRepo;
@Test
public void testInsert() throws SQLException {
testRepo.testInsert();
}
}
Я использую SQL Server 2016, и его уровень транзакции по умолчанию равен установить READ COMMITTED.
Как я могу убедиться, что вставки в хранимой процедуре фиксируются сразу во время выполнения?
Обновление
После нескольких дополнительных исследований я обнаружил, что с помощью диспетчера транзакций Spring я нахожусь в режиме неявных транзакций. Но когда я им не пользуюсь, я в автокоммите. Другими словами, select @@OPTIONS & 2
возвращает 2
с менеджером транзакций Spring и 0
без него. Итак, я думаю, это объясняет, почему я вижу различия в том, когда вставка фиксируется. Если это правильно, то мне просто нужно знать, как настроить автокоммит. Режим по умолчанию должен был измениться либо с помощью Spring, либо с драйвером SQL Server jdb c (я использовал 4.2, а сейчас использую 8.2.0.jre8).
Обновление 2
Почему так важно, чтобы какой-то другой процесс мог видеть вставку в mytempTable до завершения хранимой процедуры? Потому что в производственной хранимой процедуре она выполняет вставку, вызывает какую-то службу (которая, как я полагаю, выбирает данные из этой строки и вставляет данные в другую таблицу), а затем данные sp waitfor
отображаются в таблице, вставленной служба. Таким образом, в случае, если служба не видит вставку, хранимая процедура зависает, ожидая вставки службы в другую таблицу.
Я думаю, что решение состоит в том, чтобы не использовать явную транзакцию, а просто позволить SQL Серверу по умолчанию для автоматической фиксации. К сожалению, это также означает отсутствие отката, если что-то пойдет не так в хранимой процедуре. Но, учитывая, что хранимая процедура и служба являются сторонними компонентами, которые я не могу изменить, я полагаю, что это мой единственный вариант. Все еще задаюсь вопросом, почему поведение отличалось между Spring Boot 1.5 и 2.x или драйвером JDB C.
Обновление 3
Оказывается, что нет Разница в поведении между Spring Boot 1.5 и 2.x или версиями драйвера JDB C. То есть вставки никогда не происходят до тех пор, пока транзакция не завершится. Причина, по которой я наблюдал разницу в поведении, связана с тем фактом, что я тестировал с использованием Spring Boot 1.5 в более старом проекте и что более старый проект представляет собой составной проект с двумя источниками данных и двумя менеджерами транзакций в отличие от моего Spring Boot 2. х проект. Не уверен, почему это или что заставило бы вставку немедленно произойти в старом проекте, но это делает.
В любом случае, просматривая SQL Журналы сервера, я могу подтвердить, что независимо от версии Spring / JDB C, он вставляется немедленно, когда включен режим автоматической фиксации.