Com.microsoft.sqlserver.jdbc.sqlserverexception: поток закрыт

Я использую mssql-jdbc-12.2.0.jre8.jar и HikariCP-4.0.3.jar для подключения к базе данных Microsoft SQL Server.

Версия SQL Server: Microsoft SQL Server 2012 - 11.0.5548.0 (X64) Sep 6 2014 17:19:28 Copyright (c) Microsoft Corporation Enterprise Edition (64-bit) on Windows NT 6.3 <X64> (Build 9600: ) (Hypervisor)

Спящая версия: hibernate-core-5.6.11.Final

JRE-версия: jre1.8.0_281

Версия Apache Tomcat: 9.0.71

Версия Springboot: 2.7.4

Конфигурация Spring DataSource:

spring.datasource.url=jdbc:sqlserver://mydatabaseServer:51803;databaseName=mydatabaseName;encrypt=false;trustServerCertificate=true;socketTimeout=60000
spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.password = mypassword
spring.datasource.testWhileIdle = true
spring.datasource.test-on-borrow=true
spring.datasource.validationQuery = SELECT 1
spring.datasource.sql-script-encoding=UTF-8
spring.datasource.username = myusername
spring.datasource.hikari.pool-name=myPool
spring.datasource.hikari.maximum-pool-size=300
spring.datasource.hikari.connectionTimeout=80000 
spring.datasource.hikari.max-lifetime=300000
spring.datasource.hikari.idle-timeout=60000
spring.datasource.hikari.leakDetectionThreshold=300000
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.SQLServer2012Dialect
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
spring.jpa.open-in-view=false
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy

Запрос, вызывающий проблему, возвращает максимум 10 строк следующим образом:

@Repository
@Transactional(readOnly = true)
@Log4j2
public class SearchService {

    @PersistenceContext
    private EntityManager entityManager;
    
    public List<Request> searchRequests(SearchModel searchModel, int pageNumber) {
    

        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
        CriteriaQuery<Request> criteriaQuery = criteriaBuilder.createQuery(Request.class);
        Root<Request> requestRoot = criteriaQuery.from(Request.class);
        requestRoot.alias("r");
        
        Predicate predicate = createConditions(requestRoot, criteriaBuilder, searchModel);
        criteriaQuery.select(requestRoot);
        Order orderBy = criteriaBuilder.desc(requestRoot.get("id"));
        String orderByProperty = searchModel.getOrderBy();
        criteriaQuery.where(predicate).orderBy(orderBy);

        // pageSize is 10
        // searchModel.getMaxResult() = 10
        // for pageNumber 1 startFrom will be 0 and maxResult will be 10
        int startFrom = (pageNumber - 1) * searchModel.getPageSize();
        List<Request> result = entityManager.createQuery(criteriaQuery).setMaxResults(searchModel.getMaxResult())
                .setFirstResult(startFrom).getResultList();
        return result;
    
    }
    

}

Вышеупомянутая установка отлично работает долгое время, но в последнее время я иногда получаю множество следующих исключений: com.microsoft.sqlserver.jdbc.sqlserverexception: the stream is closed на линии :

entityManager.createQuery(criteriaQuery).setMaxResults(searchModel.getMaxResult())
                    .setFirstResult(startFrom).getResultList();

Это переводится как:

SELECT * FROM request ORDER BY id OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY;

при выполнении этого запроса непосредственно из SQL Server требуется 10 мс и когда поток закрывается, возникает проблема, в инструментах мониторинга я вижу, что он закрывается в этом запросе несколько раз!

Примечание. Объект/таблица запроса, из которой я выбираю, не имеет отношений Eager и не имеет двоичных столбцов, но имеет два столбца varchar (MAX), а максимальная достигнутая длина составила 5368.

что может быть причиной этой проблемы? может ли это быть связано с приложением или проблемой с базой данных/сервером Windows?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Версия Java на основе версии загрузки
Версия Java на основе версии загрузки
Если вы зайдете на официальный сайт Spring Boot , там представлен start.spring.io , который упрощает создание проектов Spring Boot, как показано ниже.
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
2
0
72
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Исключение «поток закрыт»… довольно расплывчато.

Предполагая, что проблем с сетью нет, а журналы SQL Server не показывают никаких других более подробных сообщений об ошибках, или у самого сервера нет проблем с ЦП/памятью/дисковым пространством, вы можете подумать:

  • Проверьте настройки пула соединений HikariCP. Возможно, вы захотите настроить параметры max-lifetime, idle-timeout и leakDetectionThreshold, чтобы соединения не закрывались преждевременно или удерживались слишком долго.

  • Оптимизируйте свой запрос. Несмотря на то, что сам запрос работает хорошо при выполнении непосредственно на SQL Server, вы все равно можете попытаться оптимизировать запрос, добавив соответствующие индексы в таблицу Request или используя разбиение на страницы с более эффективным подходом, таким как с помощью пагинации на основе набора ключей.

Попробуйте также поймать исключение с более подробной информацией, как, например, (из «Как поймать ИСКЛЮЧЕНИЯ Hibernate SQL ВЕСНОЙ»):

import javax.persistence.PersistenceException;
import org.hibernate.exception.JDBCConnectionException;
import org.springframework.dao.DataAccessException;

@Repository
@Transactional(readOnly = true)
@Log4j2
public class SearchService {

    @PersistenceContext
    private EntityManager entityManager;

    public List<Request> searchRequests(SearchModel searchModel, int pageNumber) {
        List<Request> result = new ArrayList<>();

        try {
            CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
            CriteriaQuery<Request> criteriaQuery = criteriaBuilder.createQuery(Request.class);
            Root<Request> requestRoot = criteriaQuery.from(Request.class);
            requestRoot.alias("r");

            Predicate predicate = createConditions(requestRoot, criteriaBuilder, searchModel);
            criteriaQuery.select(requestRoot);
            Order orderBy = criteriaBuilder.desc(requestRoot.get("id"));
            String orderByProperty = searchModel.getOrderBy();
            criteriaQuery.where(predicate).orderBy(orderBy);

            int startFrom = (pageNumber - 1) * searchModel.getPageSize();
            result = entityManager.createQuery(criteriaQuery).setMaxResults(searchModel.getMaxResult())
                    .setFirstResult(startFrom).getResultList();
        } catch (PersistenceException | DataAccessException e) {
            if (e.getCause() instanceof JDBCConnectionException) {
                log.error("JDBC connection exception occurred: {}", e.getMessage(), e);
            } else {
                log.error("An exception occurred while executing the search query: {}", e.getMessage(), e);
            }
        } catch (Exception e) {
            log.error("An unexpected exception occurred while executing the search query: {}", e.getMessage(), e);
        }

        return result;
    }
}

Я завернул выполнение запроса в блок try-catch, чтобы перехватывать любые PersistenceException, DataAccessException или другие общие исключения. Если происходит JDBCConnectionException, оно будет зарегистрировано с определенным сообщением. Для других исключений будет зарегистрировано более общее сообщение об ошибке. Это должно помочь вам определить и диагностировать любые проблемы, которые могут возникнуть во время выполнения запроса.

Ошибка, которую вы видите, предполагает, что соединение с SQL Server теряется либо из-за проблемы с сетью, либо из-за проблемы с конфигурацией пула соединений с базой данных.

Вот несколько вещей, на которые вы, возможно, захотите обратить внимание:

  • Database Connection Pooling: HikariCP — очень надежное соединение pool и необычно сталкиваться с такими проблемами. Однако возможно, что некоторые параметры конфигурации могут быть не оптимально для вашего варианта использования. можно попробовать изменить конфигурацию настройки HikariCP:
  • max-lifetime: Это свойство определяет максимальное время жизни соединение в пуле. Как только соединение превысит этот порог, он будет удален из пула. Значение 0 указывает на отсутствие максимального время жизни (бесконечное время жизни), что не рекомендуется. По умолчанию значение 1800000 (30 минут). Ваша текущая стоимость 300000 (5 минут), что может быть слишком мало. Можно попробовать увеличить.
  • idle-timeout: Это свойство управляет максимальным количеством времени, которое соединение может бездействовать в пуле. Значение по умолчанию 600000 (10 минут). Ваше текущее значение составляет 60000 (1 минута), что также может быть слишком низким. Можно попробовать увеличить.
  • Database Server: проверьте, нет ли проблем с базой данных сам сервер. Могут быть проблемы с сетью или сервер может быть преждевременное закрытие соединений. Ваш администратор базы данных должен быть в состоянии помочь с этот.
  • Network Issues: Проблемы с сетью также могут вызывать эту ошибку. Если между вашим приложением и сервер базы данных, это может привести к закрытию потока. Проверять для любых сетевых проблем на пути между вашим приложением и база данных.
  • JDBC Driver: Драйвер JDBC также может быть фактором. Попробуйте обновить до последняя версия драйвера JDBC для SQL Server, если вы еще не уже.
  • Query Execution Time: Хотя вы упомянули, что выполнение запроса быстро при запуске непосредственно на сервере, могут быть сценарии, когда это занимает больше времени. Это потенциально может привести к тайм-аутам. Ты можешь профилируйте свой запрос, чтобы он всегда выполнялся в разумные сроки.

Это сложная проблема для отладки, поскольку она носит прерывистый характер. Возможно, вам придется попробовать несколько из этих предложений, чтобы увидеть, поможет ли какое-либо из них. Не забудьте проверить журналы вашего сервера, как для вашего сервера приложений, так и для SQL Server, так как они могут дать больше информации о том, что вызывает проблему.

Еще один сгенерированный ответ...

Olivier 14.06.2023 09:21

Другие вопросы по теме