当前位置:首页 > 后端开发 > 正文

Java如何查询账户余额

在Java中查询余额通常涉及数据库操作,通过JDBC连接数据库后执行SQL查询语句(如SELECT balance FROM accounts WHERE id=?),获取结果集并解析数值,需确保资源关闭和异常处理,保证数据安全与程序健壮性。

从数据库查询余额(MySQL示例)

适用于账户余额存储在关系型数据库的场景,需注意防范SQL注入。

import java.sql.*;
public class BalanceQuery {
    // 数据库配置
    private static final String URL = "jdbc:mysql://localhost:3306/user_db";
    private static final String USER = "root";
    private static final String PASSWORD = "securePassword123";
    public static double getBalance(String userId) {
        String sql = "SELECT balance FROM account WHERE user_id = ?";  // 使用预编译防SQL注入
        try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
             PreparedStatement stmt = conn.prepareStatement(sql)) {
            stmt.setString(1, userId);  // 绑定参数
            ResultSet rs = stmt.executeQuery();
            if (rs.next()) {
                return rs.getDouble("balance");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return 0.0;  // 默认返回0或抛出自定义异常
    }
}

关键点:

  • 使用PreparedStatement防止SQL注入。
  • 资源自动关闭(try-with-resources)。
  • 生产环境需配置连接池(如HikariCP)。

调用第三方API查询余额

适用于对接支付平台(如支付宝、微信支付)或银行接口。

Java如何查询账户余额  第1张

import java.net.HttpURLConnection;
import java.net.URL;
import org.json.JSONObject;
public class ApiBalanceQuery {
    public static double getApiBalance(String apiKey, String userId) {
        try {
            URL url = new URL("https://api.payment.com/balance?userId=" + userId);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setRequestProperty("Authorization", "Bearer " + apiKey);  // 认证头
            if (conn.getResponseCode() == 200) {
                String response = new String(conn.getInputStream().readAllBytes());
                JSONObject json = new JSONObject(response);
                return json.getDouble("availableBalance");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return -1;  // 错误码需按业务设计
    }
}

关键点:

  • 使用HTTPS保证传输安全。
  • 敏感信息(如API Key)应存储在环境变量或配置中心。
  • 推荐使用OkHttpSpring RestTemplate等成熟HTTP客户端。

从缓存查询余额(Redis示例)

适用于高并发场景,减少数据库压力。

import redis.clients.jedis.Jedis;
public class CacheBalanceQuery {
    public static double getCachedBalance(String userId) {
        try (Jedis jedis = new Jedis("localhost", 6379)) {  // 连接Redis
            String key = "balance:" + userId;
            String cachedBalance = jedis.get(key);
            if (cachedBalance != null) {
                return Double.parseDouble(cachedBalance);
            } else {
                // 缓存未命中时从数据库加载
                double dbBalance = getBalanceFromDB(userId); 
                jedis.setex(key, 60, String.valueOf(dbBalance));  // 缓存60秒
                return dbBalance;
            }
        }
    }
    private static double getBalanceFromDB(String userId) {
        // 模拟数据库查询(实现参考第一部分)
        return 1500.0; 
    }
}

关键点:

  • 设置缓存过期时间(setex),避免脏数据。
  • 缓存穿透处理:空值缓存或布隆过滤器。
  • 集群环境使用JedisCluster

安全与性能优化建议

  1. 安全性:
    • 敏感操作需身份验证(如JWT令牌)。
    • 余额变更时加锁(数据库悲观锁或Redis分布式锁)。
    • 日志记录关键操作(使用Log4j或SLF4J)。
  2. 性能:
    • 数据库查询添加索引(如user_id字段)。
    • 批量查询时用IN语句减少连接次数。
    • 异步更新缓存(如MQ消息队列)。
  3. 事务:
    • 涉及余额增减时,用Spring @Transactional保证原子性。

常见问题解决

  • Q:余额显示不一致?
    A:检查缓存与数据库同步机制,确保更新操作后清除缓存。
  • Q:高并发导致超扣?
    A:使用SELECT ... FOR UPDATE或乐观锁(版本号机制)。
  • Q:第三方API调用慢?
    A:添加熔断机制(如Resilience4j)和超时设置。

引用说明:

  • MySQL官方文档:Prepared Statements
  • Redis命令参考:SETEX
  • OWASP SQL注入防护指南:SQL Injection Prevention
  • 支付宝开放平台API文档:账户余额查询

代码示例需根据实际业务调整,生产环境建议结合Spring Boot框架,并遵循各平台安全规范。

0