最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

java - Getting exception "Not a navigable ResultSet" from JDBCTemplate query against a MySQL database in Sprin

programmeradmin5浏览0评论

We have a Spring Boot application, written in Kotlin, which runs in a container on Digital Ocean App Platform.

Versions:

  • MySQL 8.0.30
  • Kotlin 2.0.20
  • Spring Boot 3.4.2
  • HikariCP 3.4.5
  • MySQL Connector/J 9.1.0

At, seemingly random, times, we're getting errors from our select queries that indicate that the result set was "Not a navigable ResultSet".

2025-02-18T14:37:44.866 [join-backend-v3-prod-85f5d9c488-scsgt] [http-nio-0.0.0.0-8080-exec-5] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - [] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
.springframework.dao.TransientDataAccessResourceException: PreparedStatementCallback; SQL [select 
    u.uid,
    first_name,
    last_name,
    email,
    ss.end_datetime is not null and ss.end_datetime > current_timestamp() as subscription_active,
    locale,
    time_zone,
    is_admin,
    exists(select uid from blacklisted_users where blacklisted_users.uid = u.uid) as is_blacklisted
from users u
left join subscription_summaries ss on u.uid = ss.uid
where u.uid = ?
and auth_token = ?]; Not a navigable ResultSet.
    at .springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:124)
    at .springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:107)
    at .springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:116)
    at .springframework.jdbc.core.JdbcTemplate.translateException(JdbcTemplate.java:1556)
    at .springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:677)
    at .springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:723)
    at .springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:748)
    at .springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:178)
    at .springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:186)
    at cc.join.backend.repositories.SpringUserRepository.fetchPrincipalByIdAndAuthToken(SpringUserRepository.kt:38)
    at cc.join.backend.spring.JoinAuthenticationProvider.retrieveUser(JoinAuthenticationProvider.kt:28)
    at .springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:133)
    at .springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:182)
    at cc.join.backend.spring.JoinAuthenticationTokenFilter.doFilterInternal(JoinAuthenticationTokenFilter.kt:56)
    at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
    at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
    at cc.join.backend.spring.JoinInternalJwtFilter.doFilterInternal(JoinInternalJwtFilter.kt:59)
    at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
    at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
    at cc.join.backend.spring.ActuatorApiKeyFilter.doFilterInternal(ActuatorApiKeyFilter.kt:41)
    at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
    at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
    at .springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91)
    at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
    at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
    at .springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
    at .springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
    at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
    at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
    at .springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:82)
    at .springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:69)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
    at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
    at .springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62)
    at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
    at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
    at .springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42)
    at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
    at .springframework.security.web.ObservationFilterChainDecorator$AroundFilterObservation$SimpleAroundFilterObservation.lambda$wrap$0(ObservationFilterChainDecorator.java:323)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:224)
    at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
    at .springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233)
    at .springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191)
    at .springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
    at .springframework.web.servlet.handler.HandlerMappingIntrospector.lambda$createCacheFilter$3(HandlerMappingIntrospector.java:243)
    at .springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
    at .springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:74)
    at .springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration$CompositeFilterChainProxy.doFilter(WebMvcSecurityConfiguration.java:238)
    at .springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:362)
    at .springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:278)
    at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
    at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    at .springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
    at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    at .springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
    at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
    at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    at .zalando.logbook.servlet.LogbookFilter.doFilter(LogbookFilter.java:76)
    at .zalando.logbook.servlet.SecureLogbookFilter.doFilter(SecureLogbookFilter.java:32)
    at .zalando.logbook.servlet.HttpFilter.doFilter(HttpFilter.java:32)
    at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
    at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    at .springframework.web.filter.ServerHttpObservationFilter.doFilterInternal(ServerHttpObservationFilter.java:114)
    at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
    at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    at .springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
    at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    at .apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
    at .apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
    at .apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483)
    at .apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
    at .apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
    at .apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at .apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:731)
    at .apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
    at .apache.coyote.http11.Http11Processor.service(Http11Processor.java:397)
    at .apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
    at .apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905)
    at .apache.tomcat.util.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)
    at .apache.tomcat.util.SocketProcessorBase.run(SocketProcessorBase.java:52)
    at .apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
    at .apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
    at .apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
    at java.base/java.lang.Thread.run(Unknown Source)
Caused by: java.sql.SQLException: Not a navigable ResultSet.
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:121)
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:89)
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:81)
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:55)
    at com.mysql.cj.jdbc.result.ResultSetImpl.next(ResultSetImpl.java:1807)
    at com.zaxxer.hikari.pool.HikariProxyResultSet.next(HikariProxyResultSet.java)
    at cc.join.backend.repositories.SpringUserRepository.joinPrincipalResultSetExtractor$lambda$3(SpringUserRepository.kt:64)
    at .springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:733)
    at .springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:658)
    ... 99 common frames omitted

The code that executes the query is:

import java.time.DateTimeException
import java.time.ZoneId
import java.time.zone.ZoneRulesException
import java.util.Locale
import javax.sql.DataSource

@Repository
class SpringUserRepository(dataSource: DataSource) {
    private val jdbcTemplate = NamedParameterJdbcTemplate(dataSource)

    /** Fetch a user with the given userId and token exists in the database. If no user with
     * the provided [userId] and [token] is found, returns null. */
    fun fetchPrincipalByIdAndAuthToken(userId: Long, token: String): JoinPrincipal? {
        val sql = """
            select 
                u.uid,
                first_name,
                last_name,
                email,
                ss.end_datetime is not null and ss.end_datetime > current_timestamp() as subscription_active,
                locale,
                time_zone,
                is_admin,
                exists(select uid from blacklisted_users where blacklisted_users.uid = u.uid) as is_blacklisted
            from users u
            left join subscription_summaries ss on u.uid = ss.uid
            where u.uid = :uid
            and auth_token = :authToken
        """.trimIndent()
        return jdbcTemplate.query(sql, mapOf("uid" to userId, "authToken" to token), joinPrincipalResultSetExtractor)
    }
    
    private val joinPrincipalResultSetExtractor: ResultSetExtractor<JoinPrincipal> = ResultSetExtractor { resultSet ->
        if (resultSet.next()) {
            val isBlacklisted = resultSet.getBoolean("is_blacklisted")

            val timeZone: ZoneId = resultSet.getString("time_zone")
                ?.takeIf { it.isNotBlank() }
                ?.let {
                    try {
                        ZoneId.of(it)
                    } catch (zoneRulesException: ZoneRulesException) {
                        null
                    } catch (dateTimeException: DateTimeException) {
                        null
                    }
                }
                ?: StaticSettings.DEFAULT_ZONE_ID

            JoinPrincipal(
                id = resultSet.getLong("uid"),
                firstName = resultSet.getString("first_name"),
                locale = Locale.of(resultSet.getString("locale").ifEmpty { "en" }),
                timeZone = timeZone,
                isSubscriptionActive = !isBlacklisted && resultSet.getBoolean("subscription_active"),
                isAdmin = resultSet.getBoolean("is_admin"),
                isBlacklisted = isBlacklisted,
            )
        } else {
            null
        }
    }
}

This query could result in zero rows returned, but, as it's a select query, ResultSet.next() should still work, returning false. We see the same thing with other queries that potentially return 0 rows.

Datasource configuration:

spring.datasource:
    # Our database contains zero dates and datetimes unfortunately, so we have the JDBC driver convert these to NULLs.
    url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:join}?zeroDateTimeBehavior=convertToNull&rewriteBatchedStatements=true&serverTimezone=UTC&auto
    username: ${DB_USER}
    password: ${DB_PASSWORD}
    hikari:
      data-source-properties:
        # The MySQL JDBC driver does not set a socket timeout by default. When the connection to the database gets
        # severed without a normal TCP shutdown, this can result in database connections and not being available
        # for the application.
        # See  for more information.
        socketTimeout: 30000

      # See  for documentation about the following properties:

      # Maximum amount of time that a connection will be tested for aliveness. This value must be less than the
      # connection-timeout.
      validation-timeout: 4_000
      # when creating a new database connection, fail after 5 seconds when no connection can be established. If it
      # takes longer than this, chances are that high that it will be impossible to get a connection.
      connection-timeout: 5_000
      # Regularly check database connections for aliveness. This prevents database code from being handed a connection
      # that has been severed.
      keepalive-time: 60_000
      # maximum nr of connections. We're not setting 'minimum-idle', so this will be a fixed-size pool.
      maximum-pool-size: 25
      # Whenever a connection is not returned to the pool within 10 seconds, mark it as having been leaked. = 10_000
      leak-detection-threshold: 10_000

The weird thing is that most of the time, things work perfectly. It seems rather random, and what does not help is that we cannot find any similar issues on Google nor this site.

Because we had seen the same error on our development environment, we have tried to trigger the error by performing a load test on the development environment. Unfortunately, this did not trigger the error.

We're in contact with Digital Ocean support. They indicate not having seen any database or network errors around the times that the problem occurred.

We have a Spring Boot application, written in Kotlin, which runs in a container on Digital Ocean App Platform.

Versions:

  • MySQL 8.0.30
  • Kotlin 2.0.20
  • Spring Boot 3.4.2
  • HikariCP 3.4.5
  • MySQL Connector/J 9.1.0

At, seemingly random, times, we're getting errors from our select queries that indicate that the result set was "Not a navigable ResultSet".

2025-02-18T14:37:44.866 [join-backend-v3-prod-85f5d9c488-scsgt] [http-nio-0.0.0.0-8080-exec-5] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - [] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
.springframework.dao.TransientDataAccessResourceException: PreparedStatementCallback; SQL [select 
    u.uid,
    first_name,
    last_name,
    email,
    ss.end_datetime is not null and ss.end_datetime > current_timestamp() as subscription_active,
    locale,
    time_zone,
    is_admin,
    exists(select uid from blacklisted_users where blacklisted_users.uid = u.uid) as is_blacklisted
from users u
left join subscription_summaries ss on u.uid = ss.uid
where u.uid = ?
and auth_token = ?]; Not a navigable ResultSet.
    at .springframework.jdbc.support.SQLStateSQLExceptionTranslator.doTranslate(SQLStateSQLExceptionTranslator.java:124)
    at .springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:107)
    at .springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:116)
    at .springframework.jdbc.core.JdbcTemplate.translateException(JdbcTemplate.java:1556)
    at .springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:677)
    at .springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:723)
    at .springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:748)
    at .springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:178)
    at .springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:186)
    at cc.join.backend.repositories.SpringUserRepository.fetchPrincipalByIdAndAuthToken(SpringUserRepository.kt:38)
    at cc.join.backend.spring.JoinAuthenticationProvider.retrieveUser(JoinAuthenticationProvider.kt:28)
    at .springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:133)
    at .springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:182)
    at cc.join.backend.spring.JoinAuthenticationTokenFilter.doFilterInternal(JoinAuthenticationTokenFilter.kt:56)
    at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
    at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
    at cc.join.backend.spring.JoinInternalJwtFilter.doFilterInternal(JoinInternalJwtFilter.kt:59)
    at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
    at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
    at cc.join.backend.spring.ActuatorApiKeyFilter.doFilterInternal(ActuatorApiKeyFilter.kt:41)
    at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
    at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
    at .springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91)
    at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
    at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
    at .springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90)
    at .springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75)
    at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
    at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
    at .springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:82)
    at .springframework.security.web.context.SecurityContextHolderFilter.doFilter(SecurityContextHolderFilter.java:69)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
    at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
    at .springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62)
    at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:227)
    at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
    at .springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42)
    at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
    at .springframework.security.web.ObservationFilterChainDecorator$AroundFilterObservation$SimpleAroundFilterObservation.lambda$wrap$0(ObservationFilterChainDecorator.java:323)
    at .springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.doFilter(ObservationFilterChainDecorator.java:224)
    at .springframework.security.web.ObservationFilterChainDecorator$VirtualFilterChain.doFilter(ObservationFilterChainDecorator.java:137)
    at .springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233)
    at .springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191)
    at .springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
    at .springframework.web.servlet.handler.HandlerMappingIntrospector.lambda$createCacheFilter$3(HandlerMappingIntrospector.java:243)
    at .springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:113)
    at .springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:74)
    at .springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration$CompositeFilterChainProxy.doFilter(WebMvcSecurityConfiguration.java:238)
    at .springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:362)
    at .springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:278)
    at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
    at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    at .springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
    at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    at .springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
    at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
    at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    at .zalando.logbook.servlet.LogbookFilter.doFilter(LogbookFilter.java:76)
    at .zalando.logbook.servlet.SecureLogbookFilter.doFilter(SecureLogbookFilter.java:32)
    at .zalando.logbook.servlet.HttpFilter.doFilter(HttpFilter.java:32)
    at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
    at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    at .springframework.web.filter.ServerHttpObservationFilter.doFilterInternal(ServerHttpObservationFilter.java:114)
    at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
    at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    at .springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    at .springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
    at .apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
    at .apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
    at .apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
    at .apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
    at .apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483)
    at .apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
    at .apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
    at .apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at .apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:731)
    at .apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
    at .apache.coyote.http11.Http11Processor.service(Http11Processor.java:397)
    at .apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
    at .apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905)
    at .apache.tomcat.util.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)
    at .apache.tomcat.util.SocketProcessorBase.run(SocketProcessorBase.java:52)
    at .apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
    at .apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
    at .apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
    at java.base/java.lang.Thread.run(Unknown Source)
Caused by: java.sql.SQLException: Not a navigable ResultSet.
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:121)
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:89)
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:81)
    at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:55)
    at com.mysql.cj.jdbc.result.ResultSetImpl.next(ResultSetImpl.java:1807)
    at com.zaxxer.hikari.pool.HikariProxyResultSet.next(HikariProxyResultSet.java)
    at cc.join.backend.repositories.SpringUserRepository.joinPrincipalResultSetExtractor$lambda$3(SpringUserRepository.kt:64)
    at .springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:733)
    at .springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:658)
    ... 99 common frames omitted

The code that executes the query is:

import java.time.DateTimeException
import java.time.ZoneId
import java.time.zone.ZoneRulesException
import java.util.Locale
import javax.sql.DataSource

@Repository
class SpringUserRepository(dataSource: DataSource) {
    private val jdbcTemplate = NamedParameterJdbcTemplate(dataSource)

    /** Fetch a user with the given userId and token exists in the database. If no user with
     * the provided [userId] and [token] is found, returns null. */
    fun fetchPrincipalByIdAndAuthToken(userId: Long, token: String): JoinPrincipal? {
        val sql = """
            select 
                u.uid,
                first_name,
                last_name,
                email,
                ss.end_datetime is not null and ss.end_datetime > current_timestamp() as subscription_active,
                locale,
                time_zone,
                is_admin,
                exists(select uid from blacklisted_users where blacklisted_users.uid = u.uid) as is_blacklisted
            from users u
            left join subscription_summaries ss on u.uid = ss.uid
            where u.uid = :uid
            and auth_token = :authToken
        """.trimIndent()
        return jdbcTemplate.query(sql, mapOf("uid" to userId, "authToken" to token), joinPrincipalResultSetExtractor)
    }
    
    private val joinPrincipalResultSetExtractor: ResultSetExtractor<JoinPrincipal> = ResultSetExtractor { resultSet ->
        if (resultSet.next()) {
            val isBlacklisted = resultSet.getBoolean("is_blacklisted")

            val timeZone: ZoneId = resultSet.getString("time_zone")
                ?.takeIf { it.isNotBlank() }
                ?.let {
                    try {
                        ZoneId.of(it)
                    } catch (zoneRulesException: ZoneRulesException) {
                        null
                    } catch (dateTimeException: DateTimeException) {
                        null
                    }
                }
                ?: StaticSettings.DEFAULT_ZONE_ID

            JoinPrincipal(
                id = resultSet.getLong("uid"),
                firstName = resultSet.getString("first_name"),
                locale = Locale.of(resultSet.getString("locale").ifEmpty { "en" }),
                timeZone = timeZone,
                isSubscriptionActive = !isBlacklisted && resultSet.getBoolean("subscription_active"),
                isAdmin = resultSet.getBoolean("is_admin"),
                isBlacklisted = isBlacklisted,
            )
        } else {
            null
        }
    }
}

This query could result in zero rows returned, but, as it's a select query, ResultSet.next() should still work, returning false. We see the same thing with other queries that potentially return 0 rows.

Datasource configuration:

spring.datasource:
    # Our database contains zero dates and datetimes unfortunately, so we have the JDBC driver convert these to NULLs.
    url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:join}?zeroDateTimeBehavior=convertToNull&rewriteBatchedStatements=true&serverTimezone=UTC&auto
    username: ${DB_USER}
    password: ${DB_PASSWORD}
    hikari:
      data-source-properties:
        # The MySQL JDBC driver does not set a socket timeout by default. When the connection to the database gets
        # severed without a normal TCP shutdown, this can result in database connections and not being available
        # for the application.
        # See https://github/brettwooldridge/HikariCP/wiki/Rapid-Recover for more information.
        socketTimeout: 30000

      # See https://github/brettwooldridge/HikariCP for documentation about the following properties:

      # Maximum amount of time that a connection will be tested for aliveness. This value must be less than the
      # connection-timeout.
      validation-timeout: 4_000
      # when creating a new database connection, fail after 5 seconds when no connection can be established. If it
      # takes longer than this, chances are that high that it will be impossible to get a connection.
      connection-timeout: 5_000
      # Regularly check database connections for aliveness. This prevents database code from being handed a connection
      # that has been severed.
      keepalive-time: 60_000
      # maximum nr of connections. We're not setting 'minimum-idle', so this will be a fixed-size pool.
      maximum-pool-size: 25
      # Whenever a connection is not returned to the pool within 10 seconds, mark it as having been leaked. = 10_000
      leak-detection-threshold: 10_000

The weird thing is that most of the time, things work perfectly. It seems rather random, and what does not help is that we cannot find any similar issues on Google nor this site.

Because we had seen the same error on our development environment, we have tried to trigger the error by performing a load test on the development environment. Unfortunately, this did not trigger the error.

We're in contact with Digital Ocean support. They indicate not having seen any database or network errors around the times that the problem occurred.

Share Improve this question edited 12 hours ago Ilja Booij asked 14 hours ago Ilja BooijIlja Booij 11 bronze badge New contributor Ilja Booij is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct. 5
  • Please include the full stacktrace and include the code that is actually being executed that leads to this error. – M. Deinum Commented 14 hours ago
  • Yes, sorry. Full stacktrace and code added. – Ilja Booij Commented 14 hours ago
  • Is there a reason you are downgrading HikariCP from the Spring Boot managed one (5.x)? Could you add your datasource configuration as well, I wonder if you have some sort of statement caching enabled or something like that. – M. Deinum Commented 13 hours ago
  • That is good question @M.Deinum! It seems that this is something that was left over from an old pom. Changing it to remove the explicit version. – Ilja Booij Commented 12 hours ago
  • Added the datasource configuration from application.yaml – Ilja Booij Commented 12 hours ago
Add a comment  | 

1 Answer 1

Reset to default 0

Some databases only allow forward scrolling ResultSet.

Perhaps setting TYPE_SCROLL_INSENSITIVE can solve it:

Statement stmt = connection.createStatement(
    ResultSet.TYPE_SCROLL_INSENSITIVE,  // Makes ResultSet scrollable
    ResultSet.CONCUR_READ_ONLY          // Read-only mode
);
ResultSet rs = stmt.executeQuery("SELECT * FROM users");

Odd that it's intermittent, I agree.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论