Spring JDBCTemplate с пакетным обновлением источника данных Hikari ведет себя асинхронно - PullRequest
1 голос
/ 19 сентября 2019

Я работаю над веб-приложением, в котором отображаю некоторую информацию, с которой пользователь может работать.После принятия мер список должен обновиться и отразить эти изменения на веб-странице.У меня работают все отдельные части, но соединение их вместе вызывает проблемы.

Вот, по сути, код для поиска:

public List<Entry> findEntriesForIdByStatus(Long id, Status status) {

    MapSqlParameterSource paramSource = new MapSqlParameterSource();

    paramSource.addValue("id", id);

    if (null == status) {
        return template.query(FIND_ALL_ENTRIES_QUERY, paramSource, entryResultSetExtractor);
    }

    paramSource.addValue("status", status.getCode());

    List<Entry> entryWithStatus = springJdbcTemplate.query(FIND_ENTRIES_FOR_STATUS_QUERY, 
            paramSource,
            entryResultSetExtractor);

    return equipmentWithStatus;
}

И код обновления:

@Transactional("myTransactionManager")
public void expire(CustomObject customObj) {
    Timestamp expirationTime = Timestamp.valueOf(dateTimeFactory.now());

    Long id = customObj.getId();
    List<Entry> entryList = customObj.getEntryList();

    SqlParameterSource[] params = new MapSqlParameterSource[entryList.size()];
    for (int i = 0; i < entryList.size(); i++) {
        Entry entry = entryList.get(i);
        MapSqlParameterSource paramSource = new MapSqlParameterSource("id", id)
                .addValue("fieldA", entry.getFieldA())
                .addValue("fieldB", entry.getFieldB())
                .addValue("expirationTime", expirationTime);
        params[i] = paramSource;
    }

    springJdbcTemplate.batchUpdate(EXPIRE_QUERY, params);
}

Шаблон представляет собой SpringJDBCNamedParameterTemplate, которым управляет Spring Boot, а источник данных является экземпляром com.zaxxer.hikari.HikariDataSource.

Метод поиска вызывается при загрузке страницы и возвращении правильных данных.При запуске метода expire срок действия правильных записей истек, и оба метода выполняются успешно.Первоначально я связывал их во внешнем интерфейсе, используя excludeMap (rxjs / angular 7), но это было противоречиво.Иногда извлечение после истечения возвращалось, как если бы истечение не произошло, а иногда это происходит.Однако, независимо от результата, если я обновлю страницу, результаты будут пустыми, как и ожидалось.Я переключил его на цепочку вызовов на стороне сервера, чтобы посмотреть, поможет ли это вообще, и он начал возвращать результаты, как будто истечение срока не происходило все время, но после обновления страницы это работало как ожидалось.

Вот цепочка на бэкенде:

public @ResponseBody List<Entry> expireEntries(@RequestBody CustomObj customObj) {
    entryService.expire(customObj, WebUtil.getCurrentUser());
    System.out.println(LocalDateTime.now().toString() + ": about to retrieve");
    List<Entry> entries = entryService.findEntriesByStatus(customObj.getId(), Status.NA);
    System.out.println(LocalDateTime.now().toString() + ": it's done retrieving");
    return equips;
}

Сервисы в значительной степени просто вызывают DAO без особого перерыва между ними.Выходные данные журнала аналогичны приведенным ниже:

не работает

2019-09-19T13: 33: 50,998: собирается удалить
2019-09-19T13: 33: 51.050: завершено удаление
2019-09-19T13: 33: 51.246: готово к извлечению
13: 33: 51.465 [http-nio-8080-exec-3] INFO EntryDAO - запрос для родителя 27 со статусом= NA вернул 364 и занял 219 миллисекунд
13: 33: 51.466 [http-nio-8080-exec-3] INFO EntryService - запрос для родителя 27 и статус NA вернул 364
2019-09-19T13: 33:51.466: завершено получение

обработано

2019-09-19T13: 38: 13.752: собирается удалить
2019-09-19T13: 38: 13.798:Завершено удаление
2019-09-19T13: 38: 14.112: собирается получить
13: 38: 14.120 [http-nio-8080-exec-5] INFO EntryDAO - запрос для родителя 27 с возвращенным статусом = NA0 и заняло 8 миллисекунд
13: 38: 14.120 [http-nio-8080-exec-5] INFO EntryService - запрос для родителя 27 и статус NA вернул 0
2019-09-19T13: 38: 14.120: этозавершено получение

Они относятся к тому моменту, когда цепочка была на переднем конце, но после перехода к бэкэнду, то же самое, только с «Это сделано, удаление» и «почти извлекается» ближе во времени, обычно в течение миллисекунды илидва.Похоже, что добавление двухсекундного сна между обновлением и поиском устранит проблему.Я попытался заблокировать строки для обновления и сделать методы транзакционными с помощью аннотации Spring @Transactional, но ни один из них не помог.

Насколько я могу судить, похоже, что пакетное обновление запускается, но метод Javaвозвращает до фактического завершения обновления в базе данных.Поэтому, когда запрос извлечения выполняется, он получает данные перед обновлением.Кто-нибудь может подтвердить, что это такое поведение, и если это так, есть ли способ исправить это, не взламывая его с помощью Thread.sleep?

EDIT: Вот определение компонента для диспетчера транзакций.

@Bean(name = "myDbProperties")
@Primary
@ConfigurationProperties(prefix = "spring.datasource.mydb")
public DataSourceProperties dbProperties() {
    return new DataSourceProperties();
}

@Primary
@Bean(name = "myDataSource")
@ConfigurationProperties(prefix = "spring.datasource.mydb.configuration")
public DataSource dataSource(@Qualifier("myDbProperties") DataSourceProperties dbProperties) {
    return dbProperties.initializeDataSourceBuilder().build();
}

@Bean
@Primary
@Qualifier("myTransactionManager")
public PlatformTransactionManager loadauthTransactionManager(
        @Qualifier("myDataSource") DataSource datasource) {
    return new DataSourceTransactionManager(datasource);
}

1 Ответ

0 голосов
/ 24 сентября 2019

Получается, что это был случай переосмысления, и решение было на самом деле довольно простым.Используется запрос на чтение sysdate between create and delete.Оказывается, что между включается, и так как запросы происходили в пределах результата минимального приращения времени sysdate, возвращаемого, потому что sysdate = delete.Переключение на where systimestamp >= create and systimestamp < delete устранило проблему.

...