在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查询余额
适用于对接支付平台(如支付宝、微信支付)或银行接口。
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)应存储在环境变量或配置中心。
- 推荐使用
OkHttp
或Spring 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
。
安全与性能优化建议
- 安全性:
- 敏感操作需身份验证(如JWT令牌)。
- 余额变更时加锁(数据库悲观锁或Redis分布式锁)。
- 日志记录关键操作(使用Log4j或SLF4J)。
- 性能:
- 数据库查询添加索引(如
user_id
字段)。 - 批量查询时用
IN
语句减少连接次数。 - 异步更新缓存(如MQ消息队列)。
- 数据库查询添加索引(如
- 事务:
- 涉及余额增减时,用Spring
@Transactional
保证原子性。
- 涉及余额增减时,用Spring
常见问题解决
- Q:余额显示不一致?
A:检查缓存与数据库同步机制,确保更新操作后清除缓存。 - Q:高并发导致超扣?
A:使用SELECT ... FOR UPDATE
或乐观锁(版本号机制)。 - Q:第三方API调用慢?
A:添加熔断机制(如Resilience4j)和超时设置。
引用说明:
- MySQL官方文档:Prepared Statements
- Redis命令参考:SETEX
- OWASP SQL注入防护指南:SQL Injection Prevention
- 支付宝开放平台API文档:账户余额查询
代码示例需根据实际业务调整,生产环境建议结合Spring Boot框架,并遵循各平台安全规范。
原创文章,发布者:酷盾叔,转转请注明出处:https://www.kd.cn/ask/23097.html