代码之家  ›  专栏  ›  技术社区  ›  Mahmoud Saleh

com.microsoft.sqlserver.jdbc.sqlserverexception:流已关闭

  •  0
  • Mahmoud Saleh  · 技术社区  · 2 年前

    我正在使用 mssql-jdbc-12.2.0.jre8.jar HikariCP-4.0.3.jar 连接到Microsof 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版本 : 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毫秒 当流关闭问题发生时,在监控工具中,我可以看到它在这个查询中多次关闭!

    笔记 :的 请求实体/表 我从中选择的 没有热切的关系 并且已经 没有二进制列 但它有 两个varchar(MAX)列 达到的最大长度为5368

    是什么原因导致了这个问题?它可能与应用程序有关,也可能是数据库/windows服务器问题?

    0 回复  |  直到 2 年前
        1
  •  4
  •   VonC    2 年前

    “流已关闭”的例外情况…相当模糊。

    假设没有网络问题,并且SQL Server日志没有显示任何其他更详细的错误消息,或者服务器本身没有CPU/内存/磁盘空间问题,您可能会考虑:

    • 查看您的 HikariCP connection pool settings 。您可能需要调整 max-lifetime , idle-timeout leakDetectionThreshold 设置,以确保连接不会过早关闭或保持时间过长。

    • 优化查询:尽管直接在SQL Server上执行查询时,查询本身表现良好,但您仍然可以尝试通过向 Request 表,或者使用更有效的分页方法,例如使用基于键集的分页。

    还可以尝试捕获具有更多细节的异常,例如中的(来自“ How to catch Hibernate SQL EXCEPTIONS IN SPRING "):

    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 发生时,将使用特定消息进行记录。对于其他异常,将记录一条更通用的错误消息。
    这将帮助您识别和诊断在执行查询过程中可能出现的任何问题。