我有一个grails项目,刚刚从grails-3.1.6升级到grails-5.1.7。升级后,在使用默认数据源查询 MySQL 表时经常遇到通信链路失败的问题。
例外:
WARNING [http-nio-8088-exec-2] groovy.sql.Sql$AbstractQueryCommand.execute Failed to execute: SELECT id, loa, loa_id FROM crosswalk_table WHERE client_id=:clientId AND update_status=:updateStatus; because: No operations allowed after connection closed. java.sql.SQLNonTransientConnectionException: No operations allowed after connection closed.
这个问题是在部署环境中检测到的,当我关闭电脑大约十五分钟时,该问题也在本地环境中复制。 在我的 Intellij 或本地 tomcat 控制台中,它打印异常:
14-Dec-2023 00:05:44.096 SEVERE [Tomcat JDBC Pool Cleaner[1285282956:1702488174095]] org.apache.tomcat.jdbc.pool.ConnectionPool.reconnectIfExpired Failed to re-connect connection [org.apache.tomcat.jdbc.pool.ConnectionPool@7c24cbe8] that expired because of maxAge com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
我的项目配置如下: 应用程序.yml
hibernate:
cache:
queries: false
use_second_level_cache: true
use_query_cache: false
region.factory_class: 'org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory'
dataSources:
dataSource:
pooled: true
jmxExport: true
driverClassName: com.mysql.cj.jdbc.Driver
dialect: "org.hibernate.dialect.MySQL5InnoDBDialect"
properties:
maxActive: 100
maxIdle: 25
minIdle: 5
initialSize: 5
maxWait: 10000
removeAbandoned: true
removeAbandonedTimeout: 400
logAbandoned: true
maxAge: 60000
minEvictableIdleTimeMillis: 5000
timeBetweenEvictionRunsMillis: 15000
numTestsPerEvictionRun: 3
testOnBorrow: true
testWhileIdle: true
testOnReturn: true
validationQuery: "SELECT 1"
validationQueryTimeout: 3
validationInterval: 15000
pa:
pooled: true
jmxExport: true
driverClassName: com.mysql.cj.jdbc.Driver
dialect: "org.hibernate.dialect.MySQL5InnoDBDialect"
properties:
maxActive: 100
maxIdle: 25
minIdle: 5
initialSize: 5
maxWait: 10000
removeAbandoned: true
removeAbandonedTimeout: 400
logAbandoned: true
maxAge: 60000
minEvictableIdleTimeMillis: 5000
timeBetweenEvictionRunsMillis: 15000
numTestsPerEvictionRun: 3
testOnBorrow: true
testWhileIdle: true
testOnReturn: true
validationQuery: "SELECT 1"
我已将另一个 yml 文件中的主机网址、用户名和密码外部化为:
dataSources:
dataSource:
dbCreate: none
url: jdbc:mysql://localhost:3306/everest_dev?zeroDateTimeBehavior=convertToNull&useSSL=false
username: root
password: root
pa:
dbCreate: none
url: jdbc:mysql://localhost:3306/solu_dev?zeroDateTimeBehavior=convertToNull&useSSL=false
username: root
password: root
代码示例:
@Slf4j
class LoaService {
def dataSource
def getLoaEditDataD(Map params) {
String dwClientId = params.get("dwClientId", String.class)
Sql sqlDAS
try {
sqlDAS = Sql.newInstance(dataSource)
def sqlQuery = "SELECT id, loa, loa_id FROM loa_editor_crosswalk_table " +
"WHERE client_id=:clientId AND update_status=:updateStatus;"
def sqlParams = [clientId: dwClientId, updateStatus: 'Completed', isDeleted: false]
def result = sqlDAS.rows(sqlQuery, sqlParams)
return result
} catch (Exception exc) {
exc.printStackTrace()
} finally {
if (sqlDAS != null) sqlDAS.close()
}
}
仅在使用默认数据源时才会重现此通信链路失败的问题;如果使用dataSource_pa,问题不会重现。
其他项目配置:
使用自定义的dataSource_pa解决了通信链路故障,使用GORM方法可以避免此类故障。 默认数据源是唯一的问题。因此,我必须查明这次失败的原因可能是什么。
我也在找同样的问题...