解决数据库超时问题

     最近做测试,发现Mysql 过一段时间会无法连接,导致数据库数据不一至,极其郁闷。

    下面是转一哥门的

    使用Connector/J连接MySQL数据库,程序运行较长时间后就会报以下错误:

Communications link failure,The last packet successfully received from the server was *** millisecond ago.The last packet successfully sent to the server was ***  millisecond ago。

    其中错误还会提示你修改wait_timeout或是使用Connector/J的autoReconnect属性避免该错误。

后来查了一些资料,才发现遇到这个问题的人还真不少,大部分都是使用连接池方式时才会出现这个问题,短连接应该很难出现这个问题。这个问题的原因:

    MySQL服务器默认的“wait_timeout”是28800秒即8小时,意味着如果一个连接的空闲时间超过8个小时,MySQL将自动断开该连接,而连接池却认为该连接还是有效的(因为并未校验连接的有效性),当应用申请使用该连接时,就会导致上面的报错。

    1.按照错误的提示,可以在JDBC URL中使用autoReconnect属性,实际测试时使用了autoReconnect=true& failOverReadOnly=false,不过并未起作用,使用的是5.1版本,可能真像网上所说的只对4之前的版本有效。

    2.没办法,只能修改MySQL的参数了,wait_timeout最大为31536000即1年,在my.cnf中加入:

[mysqld]

wait_timeout=31536000

interactive_timeout=31536000

重启生效,需要同时修改这两个参数。

本文链接地址为:http://zhangwei12hao.blog.163.com/blog/static/240030432011313111225150/

Java 高并发环境下数据库超时问题是一个常见的性能瓶颈,通常表现为连接超时、查询超时或事务等待超时。这类问题在高并发请求下尤为突出,可能直接导致系统响应变慢甚至雪崩。 ### 常见的数据库超时类型及原因: 1. **Connection Timeout(连接超时)** - 原因:数据库连接池中没有可用连接,新请求无法获取连接。 - 场景:高并发下连接池配置过小,或连接未及时释放。 2. **Socket Timeout / Query Timeout(查询超时)** - 原因:SQL 执行时间过长,超过了设置的查询超时阈值。 - 场景:慢 SQL、缺少索引、锁竞争、大表扫描等。 3. **Transaction Timeout(事务超时)** - 原因:事务持有锁时间过长,其他事务等待超时。 - 场景:长事务、批量操作未分批、死锁等。 --- ### 解决方案 #### 1. 合理配置数据库连接池(以 HikariCP 为例) ```java import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; public class DataSourceConfig { public static HikariDataSource createDataSource() { HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC"); config.setUsername("root"); config.setPassword("password"); // 连接池大小(根据 CPU 核数和 DB 处理能力调整) config.setMaximumPoolSize(20); config.setMinimumIdle(5); // 连接超时:等待连接的最大时间(毫秒) config.setConnectionTimeout(30000); // 30秒 // 查询超时:Statement 执行最大时间 config.setValidationTimeout(5000); // 验证连接的超时时间 // 连接最大存活时间 config.setMaxLifetime(1800000); // 30分钟 // 空闲连接超时 config.setIdleTimeout(600000); // 10分钟 return new HikariDataSource(config); } } ``` > ✅ 建议:`maximumPoolSize` 不宜过大,一般建议为 `CPU核心数 * 2 ~ 4`,避免过多线程争抢资源。 --- #### 2. 设置查询超时JDBC 层面) ```java import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class QueryWithTimeout { private final Connection connection; public QueryWithTimeout(Connection connection) { this.connection = connection; } public void queryWithTimeout() throws SQLException { String sql = "SELECT * FROM user WHERE status = ?"; try (PreparedStatement stmt = connection.prepareStatement(sql)) { // 设置查询超时为 10 秒 stmt.setQueryTimeout(10); stmt.setInt(1, 1); try (ResultSet rs = stmt.executeQuery()) { while (rs.next()) { System.out.println(rs.getString("name")); } } } } } ``` --- #### 3. 使用 Spring 的 @Transactional 设置事务超时 ```java import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class UserService { // 设置事务最大执行时间为 5 秒 @Transactional(timeout = 5) public void updateUserStatus(Long userId, int status) { // 执行更新逻辑 // 如果超过 5 秒未完成,事务将回滚并抛出 TransactionTimedOutException } } ``` --- #### 4. 优化 SQL 和索引 - 对频繁查询的字段添加索引(如 `status`, `create_time`)。 - 避免 `SELECT *`,只查需要的字段。 - 分页处理大数据集:使用 `LIMIT OFFSET` 或游标分页。 - 批量操作使用 `batch insert/update`。 --- #### 5. 引入熔断与降级机制(如 Resilience4j) ```java import io.github.resilience4j.circuitbreaker.CircuitBreaker; import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig; import io.github.resilience4j.decorators.Decorators; import java.time.Duration; import java.util.function.Supplier; public class DatabaseServiceWithCircuitBreaker { private final CircuitBreaker circuitBreaker; public DatabaseServiceWithCircuitBreaker() { CircuitBreakerConfig config = CircuitBreakerConfig.custom() .failureRateThreshold(50f) .waitDurationInOpenState(Duration.ofMillis(1000)) .slidingWindowType(CircuitBreakerConfig.SlidingWindowType.COUNT_BASED) .slidingWindowSize(5) .build(); this.circuitBreaker = CircuitBreaker.of("database", config); } public String queryUser() { Supplier<String> decoratedSupplier = Decorators.ofSupplier(() -> "query from DB") .withCircuitBreaker(circuitBreaker) .withFallback(Arrays.asList(Exception.class), e -> "fallback result") .decorate(); return decoratedSupplier.get(); } } ``` --- #### 6. 监控与日志分析 - 开启慢查询日志(MySQL): ```sql SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 2; -- 超过2秒记录 ``` - 使用 APM 工具:SkyWalking、Pinpoint、Prometheus + Grafana 监控数据库响应时间。 --- ### 总结 | 问题类型 | 解决方案 | |------------------|--------| | 连接超时 | 增大连接池、复用连接、及时关闭 | | 查询超时 | 优化 SQL、加索引、设置 queryTimeout | | 事务超时 | 缩短事务范围、避免长事务 | | 高并发压力 | 读写分离、分库分表、缓存(Redis) | | 系统稳定性 | 熔断、限流、降级 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值