数据库连接的重连

每次项目上线前都必然会确认下数据库,redis 的断线重连机制,由于事关重大,每次都要查询资料,浪费了很多时间。这次查询后在这里记录一下,作为一个检查表,避免下次再麻烦。

MySQL 的断线重连

MySQL 的 jdbc 连接字符串支持配置断线重连 autoReconnect=true,但是这种配置方式并不推荐,因为有副作用,文档节选如下:

autoReconnect

Should the driver try to re-establish stale and/or dead connections? If enabled the driver will throw an exception for a queries issued on a stale or dead connection, which belong to the current transaction, but will attempt reconnect before the next query issued on the connection in a new transaction. The use of this feature is not recommended, because it has side effects related to session state and data consistency when applications don't handle SQLExceptions properly, and is only designed to be used when you are unable to configure your application to handle SQLExceptions resulting from dead and stale connections properly. Alternatively, as a last option, investigate setting the MySQL server variable "wait_timeout" to a high value, rather than the default of 8 hours.

Default: false

https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-configuration-properties.html

所以,MySQL 的断线重连使用连接池的相关配置实现,我查看了 Alibaba Druid 和 Hikari 的配置,大同小异,即通过配置一个检测 SQL 来判断连接是否有效,如无效,则从连接池剔除。所谓重连只是从连接池 borrow 时重新创建一个连接即可。

配合 testWhileIdle 检测空闲连接的可用性,避免 MySQL 服务器端超时导致报错。

Druid 配置:

    <property name="druid.validationQuery" value="SELECT 'x'"/>
    <property name="druid.testWhileIdle" value="true"/>
    <property name="druid.testOnBorrow" value="false"/>
    <property name="druid.testOnReturn" value="false"/>

Spring Boot 配置:

    spring.datasource.testWhileIdle = true
    spring.datasource.timeBetweenEvictionRunsMillis = 60000
    spring.datasource.validationQuery = SELECT 1

Redis 的断线重连

项目使用的客户端时 lettuce,直接在代码里设置重连即可。默认重连间隔从1秒开始翻倍延长,最大30秒。

client.setOptions(ClientOptions.builder()
                .autoReconnect(true)
                .socketOptions(SocketOptions.builder()
                        .keepAlive(true)
                        .tcpNoDelay(true)
                        .build()
                )
                .build());