英文:
com.microsoft.sqlserver.jdbc.sqlserverexception: the stream is closed
问题
I am using mssql-jdbc-12.2.0.jre8.jar
and HikariCP-4.0.3.jar
to connect to Microsoft SQL Server Database.
SQL Server version is: 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 version: hibernate-core-5.6.11.Final
.
JRE version: jre1.8.0_281
.
Apache Tomcat version: 9.0.71
.
Spring Boot version: 2.7.4
.
Spring DataSource configuration:
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
The query causing the issue is returning a maximum of 10 rows as follows:
@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;
}
}
The above setup has been working fine for a long time. However, recently, there have been occasional occurrences of the following exception: com.microsoft.sqlserver.jdbc.sqlserverexception: the stream is closed
on the line:
entityManager.createQuery(criteriaQuery).setMaxResults(searchModel.getMaxResult())
.setFirstResult(startFrom).getResultList();
This query is translated to:
SELECT * FROM request ORDER BY id OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY;
When executing this query directly from SQL Server, it takes 10ms. The issue with the closed stream occurs multiple times in this query, as seen in monitoring tools.
Note: The Request
entity/table from which I am selecting has no eager relationships and no binary columns, but it does have two varchar(MAX)
columns, with the maximum length reached being 5368.
What might be causing this issue? Could it be related to the application or a database/Windows server issue?
英文:
I am using mssql-jdbc-12.2.0.jre8.jar
and HikariCP-4.0.3.jar
to connect to Microsof SQL Server Database
SQL Server version is: 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 version: hibernate-core-5.6.11.Final
JRE version: jre1.8.0_281
Apache Tomcat version: 9.0.71
Springboot version: 2.7.4
Spring DataSource configuration:
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
The query causing the issue is returning maximum 10 rows as follows:
@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;
}
}
The above setup works fine from long time, but recently sometimes I get lots of the following exception: com.microsoft.sqlserver.jdbc.sqlserverexception: the stream is closed
on the line :
entityManager.createQuery(criteriaQuery).setMaxResults(searchModel.getMaxResult())
.setFirstResult(startFrom).getResultList();
This is translated to:
SELECT * FROM request ORDER BY id OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY;
when excuting this query direct from SQL Server it takes 10ms
and when the stream is closed issue happens, in the monitoring tools I can see that it's closed in this query multiple times !
Note : the Request entity/table which I am selecting from has no Eager relationships and has no Binary columns but it has two varchar(MAX) columns and the maximum length reached was 5368
what might be causing this issue ? can it be application related or database/windows server issue ?
答案1
得分: 4
"stream is closed"异常...相当模糊。
假设没有网络问题,SQL Server日志中没有显示任何更详细的错误消息,或者服务器本身没有CPU/内存/磁盘空间问题,您可以考虑:
-
检查您的HikariCP连接池设置。您可能需要调整
max-lifetime
、idle-timeout
和leakDetectionThreshold
设置,以确保连接不会过早关闭或保持太长时间。 -
优化您的查询:虽然查询本身在直接在SQL Server上执行时似乎表现良好,但您仍然可以尝试通过为
Request
表添加适当的索引或使用更高效的方法进行分页(如使用基于键集的分页)来进一步优化查询。
还可以尝试捕获带有更多详细信息的异常,例如(来自“如何在SPRING中捕获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连接异常发生:{}", e.getMessage(), e);
} else {
log.error("在执行搜索查询时发生异常:{}", e.getMessage(), e);
}
} catch (Exception e) {
log.error("在执行搜索查询时发生意外异常:{}", e.getMessage(), e);
}
return result;
}
}
我已经在try-catch块中包装了查询执行,以捕获任何PersistenceException
、DataAccessException
或其他一般异常。如果发生JDBCConnectionException
,将记录具有特定消息的日志。对于其他异常,将记录更通用的错误消息。这应该有助于您在执行查询期间识别和诊断可能出现的任何问题。
英文:
The "stream is closed" exception is... quite vague.
Assuming there is no network issue, and the SQL Server logs not show any other more detailed error message, or the server itself has no CPU/memory/disk space issue, you might consider:
-
Review your HikariCP connection pool settings. You might want to adjust the
max-lifetime
,idle-timeout
, andleakDetectionThreshold
settings to ensure that connections are not being closed prematurely or held for too long. -
Optimize your Query: Although the query itself seems to be performing well when executed directly on the SQL Server, you can still try to optimize the query further by adding appropriate indexes to the
Request
table or by using pagination with a more efficient approach, such as using a keyset-based pagination.
Try also to catch exception with more details, as in, for instance (from "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;
}
}
I have wrapped the query execution in a try-catch block to catch any PersistenceException
, DataAccessException
, or other general exceptions. If a JDBCConnectionException
occurs, it will be logged with a specific message. For other exceptions, a more generic error message will be logged.
This should help you identify and diagnose any issues that might occur during the execution of the query.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论