SQLite Update语句无法修改数据库数据问题排查
问题分析与修复方案
导致更新无效果的核心问题
- 连接重复获取+事务未控制:你两次调用
coon.getConnection(),如果dbConnection的这个方法每次都新建连接,那查询和更新用的是两个独立连接。部分JDBC驱动默认关闭自动提交,第二个连接的更新操作不会自动持久化;而且跨连接操作会出现数据隔离问题,查的是旧数据,更新也落不了地。 - 未处理账户不存在的情况:如果
accountIdFrom对应的账户不存在,balance会保持初始值0,要么更新不到任何行,要么错误地把不存在的账户(若数据库允许)余额设为负数。 - REPLACE用法错误:
REPLACE INTO的逻辑是主键/唯一键匹配到就删旧行插新行,匹配不到就直接插新行。你替换后新增数据,说明WHERE条件没匹配到现有行,触发了插入逻辑,这不是你要的更新效果。
修复后的代码
public void balanceTransactionChange(Integer accountIdFrom, Integer accountIdTo, double amount) { // 同账户转账无需操作,按业务需求可调整 if (Objects.equals(accountIdTo, accountIdFrom)) { return; } dbConnection coon = new dbConnection(); Connection conn = null; try { conn = coon.getConnection(); // 关闭自动提交,开启事务 conn.setAutoCommit(false); // 1. 查询账户余额,用PreparedStatement防SQL注入 String querySql = "SELECT balance FROM Account WHERE id = ?"; PreparedStatement queryStmt = conn.prepareStatement(querySql); queryStmt.setInt(1, accountIdFrom); ResultSet resultSet = queryStmt.executeQuery(); double balance = 0; if (!resultSet.next()) { throw new IllegalArgumentException("账户ID " + accountIdFrom + " 不存在"); } balance = resultSet.getDouble("balance"); // 2. 可选:检查余额是否足够 if (balance < amount) { throw new IllegalStateException("账户 " + accountIdFrom + " 余额不足"); } // 3. 更新余额 String updateSql = "UPDATE Account SET balance = ? WHERE id = ?"; PreparedStatement updateStmt = conn.prepareStatement(updateSql); updateStmt.setDouble(1, balance - amount); updateStmt.setInt(2, accountIdFrom); int affectedRows = updateStmt.executeUpdate(); if (affectedRows == 0) { throw new RuntimeException("更新账户 " + accountIdFrom + " 失败,无匹配行"); } // 提交事务 conn.commit(); // 关闭资源 resultSet.close(); queryStmt.close(); updateStmt.close(); } catch (SQLException e) { // 出错回滚事务 if (conn != null) { try { conn.rollback(); } catch (SQLException ex) { ex.printStackTrace(); } } throw new RuntimeException(e); } finally { coon.closeConnection(); } }
关键修复点
- 复用单个连接:全程用同一个连接,保证查询和更新在同一个事务里,避免数据隔离问题。
- 手动控制事务:关闭自动提交,操作成功后提交,出错时回滚,确保数据一致性。
- 替换SQL拼接为PreparedStatement:既避免SQL注入风险,也提升执行效率。
- 增加异常判断:处理账户不存在、更新无匹配行的情况,避免静默失败。
- 优化同账户逻辑:同账户转账直接返回(如果业务是同账户扣钱,删掉这个判断即可)。
关于REPLACE的正确用法
如果一定要用REPLACE,应该写成REPLACE INTO Account (id, balance) VALUES (?, ?)——REPLACE是基于主键/唯一键匹配的,不需要WHERE子句。但更新余额场景下,UPDATE才是正确选择,REPLACE会删除旧行再插入,可能丢失账户其他字段的数据。
内容的提问来源于stack exchange,提问作者Liron
相关产品推荐
相关产品推荐

