Вставки не фиксируются до завершения транзакции с использованием PlatformTransactionManager - PullRequest
0 голосов
/ 13 февраля 2020

Мне нужно убедиться, что вставки фиксируются во время выполнения хранимой процедуры. При использовании 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, он вставляется немедленно, когда включен режим автоматической фиксации.

1 Ответ

0 голосов
/ 14 февраля 2020

Если выполнение хранимой процедуры следует шаблону «транзакционная запись с обратной записью» стандартных операций с сущностями, тогда обычное поведение заключается в том, что операторы SQL ставятся в очередь до тех пор, пока транзакция не завершится.

Репозитории Spring Data по умолчанию являются транзакционными, поэтому даже без явного @Transactional(transactionManager="transactionManager") в вашем тесте транзакция выполняется.

https://vladmihalcea.com/a-beginners-guide-to-jpahibernate-flush-strategies/ (при условии, что вы используете Hibernate здесь, но, вероятно, аналогичные концепции в других реализациях JPA).

Попробуйте, чтобы вызвать немедленный грипп sh:

@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional(transactionManager="transactionManager")
public class InsertRepositoryTest {

    @Autowired
    private TestRepository testRepo;

    @PersistenceContext 
    primate EntityManager em;

    @Test
    public void testInsert() throws SQLException {
        testRepo.testInsert();
        em.flush(); //write all buffered SQL statements
    }   
}
...