Java数据库资源优化实操

wen java案例 33

Java数据库资源优化实操指南

连接池优化

配置文件示例 (HikariCP)

# application.yml
spring:
  datasource:
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5
      idle-timeout: 300000
      connection-timeout: 20000
      max-lifetime: 1200000
      validation-timeout: 3000
      leak-detection-threshold: 60000

连接池监控代码

@Component
public class DataSourceHealthIndicator {
    @Autowired
    private DataSource dataSource;
    @Scheduled(fixedRate = 60000)
    public void monitorConnectionPool() {
        if (dataSource instanceof HikariDataSource) {
            HikariDataSource hikariDS = (HikariDataSource) dataSource;
            HikariPoolMXBean poolMXBean = hikariDS.getHikariPoolMXBean();
            log.info("活跃连接: {}, 空闲连接: {}, 等待线程数: {}, 总连接数: {}", 
                poolMXBean.getActiveConnections(),
                poolMXBean.getIdleConnections(), 
                poolMXBean.getThreadsAwaitingConnection(),
                poolMXBean.getTotalConnections());
        }
    }
}

SQL性能优化

慢查询日志配置

@Configuration
public class SQLPerformanceConfig {
    @Bean
    public PerformanceInterceptor performanceInterceptor() {
        PerformanceInterceptor interceptor = new PerformanceInterceptor();
        interceptor.setMaxTime(100); // 超过100ms记录慢查询
        interceptor.setFormat(true);
        return interceptor;
    }
}

批量操作优化

@Service
public class BatchOptimizationService {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    // 批量插入优化
    @Transactional
    public void batchInsert(List<User> users) {
        String sql = "INSERT INTO users(name, email, age) VALUES (?, ?, ?)";
        jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement ps, int i) throws SQLException {
                User user = users.get(i);
                ps.setString(1, user.getName());
                ps.setString(2, user.getEmail());
                ps.setInt(3, user.getAge());
            }
            @Override
            public int getBatchSize() {
                return users.size();
            }
        });
    }
    // 使用NamedParameterJdbcTemplate进行批量操作
    public void batchInsertWithNamedParams(List<User> users) {
        String sql = "INSERT INTO users(name, email, age) VALUES (:name, :email, :age)";
        SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(users.toArray());
        namedParameterJdbcTemplate.batchUpdate(sql, batch);
    }
}

事务管理优化

@Service
public class TransactionOptimizationService {
    // 事务超时设置
    @Transactional(timeout = 30)
    public void processWithTimeout() {
        // 业务逻辑
    }
    // 只读事务优化
    @Transactional(readOnly = true)
    public List<User> findUsers() {
        // 查询操作,优化数据库资源
    }
    // 事务传播行为优化
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void independentTransaction() {
        // 独立事务操作
    }
}

数据库连接泄漏检测

@Component
public class ConnectionLeakDetector {
    private static final ThreadLocal<Long> CONNECTION_START_TIME = new ThreadLocal<>();
    @EventListener
    public void handleConnectionCreated(ConnectionCreatedEvent event) {
        CONNECTION_START_TIME.set(System.currentTimeMillis());
    }
    @EventListener
    public void handleConnectionClosed(ConnectionClosedEvent event) {
        CONNECTION_START_TIME.remove();
    }
    @Scheduled(fixedRate = 60000)
    public void checkLeakConnections() {
        if (CONNECTION_START_TIME.get() != null) {
            long duration = System.currentTimeMillis() - CONNECTION_START_TIME.get();
            if (duration > 300000) { // 5分钟
                log.warn("检测到可能的数据库连接泄漏,连接持续时间: {} ms", duration);
                // 发送告警
            }
        }
    }
}

缓存优化策略

@Service
public class CacheOptimizationService {
    @Autowired
    private CacheManager cacheManager;
    // 使用Redis缓存减少数据库访问
    @Cacheable(value = "users", key = "#id", unless = "#result == null")
    public User getUserById(Long id) {
        return userRepository.findById(id).orElse(null);
    }
    // 缓存失效策略
    @CacheEvict(value = "users", key = "#user.id")
    public User updateUser(User user) {
        return userRepository.save(user);
    }
    // 批量缓存
    @Cacheable(value = "users", key = "'all_users'")
    public List<User> getAllUsers() {
        return userRepository.findAll();
    }
}

数据库查询优化

@Repository
public class QueryOptimizationRepository {
    @PersistenceContext
    private EntityManager entityManager;
    // 使用JOIN FETCH避免N+1问题
    @Query("SELECT u FROM User u JOIN FETCH u.orders WHERE u.id = :id")
    User findUserWithOrders(@Param("id") Long id);
    // 分页查询优化
    @Query(value = "SELECT * FROM users WHERE status = :status", 
           countQuery = "SELECT count(*) FROM users WHERE status = :status",
           nativeQuery = true)
    Page<User> findUsersByStatus(@Param("status") String status, Pageable pageable);
    // 使用投影减少数据传输
    @Query("SELECT new com.example.dto.UserSummary(u.id, u.name, u.email) FROM User u")
    List<UserSummary> findUserSummaries();
    // 批量更新优化
    @Modifying
    @Query("UPDATE User u SET u.status = :status WHERE u.id IN :ids")
    int batchUpdateStatus(@Param("status") String status, @Param("ids") List<Long> ids);
}

数据库资源监控

@Component
public class DatabaseResourceMonitor {
    @Autowired
    private DataSource dataSource;
    @Scheduled(fixedRate = 300000) // 5分钟执行一次
    public void monitorDatabaseResources() {
        try (Connection connection = dataSource.getConnection()) {
            DatabaseMetaData metaData = connection.getMetaData();
            // 检查数据库连接数
            String query = "SELECT COUNT(*) FROM pg_stat_activity";
            try (PreparedStatement ps = connection.prepareStatement(query);
                 ResultSet rs = ps.executeQuery()) {
                if (rs.next()) {
                    int activeConnections = rs.getInt(1);
                    log.info("当前数据库活跃连接数: {}", activeConnections);
                }
            }
            // 检查死锁
            String deadlockQuery = "SELECT * FROM pg_locks WHERE NOT granted";
            // 实现死锁检测逻辑
        } catch (SQLException e) {
            log.error("数据库资源监控失败", e);
        }
    }
}

JDBC连接优化

@Configuration
public class JDBCResourceOptimization {
    @Bean
    public DataSource dataSource() {
        HikariConfig config = new HikariConfig();
        // 连接池基本配置
        config.setJdbcUrl("jdbc:postgresql://localhost:5432/db");
        config.setUsername("user");
        config.setPassword("password");
        // 连接池优化参数
        config.setMaximumPoolSize(20);
        config.setMinimumIdle(5);
        config.setIdleTimeout(300000);
        config.setConnectionTimeout(20000);
        config.setMaxLifetime(1200000);
        // 连接测试
        config.setConnectionTestQuery("SELECT 1");
        config.setValidationTimeout(3000);
        // 性能监控
        config.setMetricRegistry(metricRegistry);
        config.setHealthCheckRegistry(healthCheckRegistry);
        return new HikariDataSource(config);
    }
}

数据库资源使用分析

@Component
public class ResourceUsageAnalyzer {
    @EventListener
    public void analyzeQueryPerformance(QueryExecutionEvent event) {
        QueryExecutionMetrics metrics = event.getMetrics();
        // 记录慢查询
        if (metrics.getExecutionTime() > 1000) {
            log.warn("慢查询告警: SQL={}, 执行时间={}ms, 返回行数={}", 
                metrics.getSql(), 
                metrics.getExecutionTime(),
                metrics.getResultSize());
        }
        // 记录大量数据返回
        if (metrics.getResultSize() > 10000) {
            log.info("大数据量返回: SQL={}, 返回行数={}", 
                metrics.getSql(), 
                metrics.getResultSize());
        }
    }
    @Scheduled(cron = "0 0 2 * * ?") // 每天凌晨2点执行
    public void generateDailyReport() {
        // 生成数据库资源使用日报
        log.info("开始生成数据库资源使用日报");
        // 收集指标
        // 生成报告
        // 发送邮件
    }
}

最佳实践总结

  1. 连接池配置优化

    Java数据库资源优化实操

    • 根据应用负载动态调整连接池大小
    • 设置合理的超时和存活时间
  2. SQL优化

    • 使用EXPLAIN分析执行计划
    • 避免SELECT *,只查询需要的字段
    • 合理使用索引
  3. 事务管理

    • 控制事务范围,避免长事务
    • 合理使用隔离级别
  4. 监控告警

    • 建立完整的监控体系
    • 设置告警阈值
  5. 定期维护

    • 清理无效连接
    • 优化数据库表结构
    • 更新统计信息

这些优化措施需要根据实际业务场景和数据库类型进行适当调整,建议在生产环境进行充分的性能测试后再实施。

抱歉,评论功能暂时关闭!