使用JDBC PreparedStatement向MySQL插入类别列表无数据生效问题
根因定位与修复方案
你遇到的“无异常抛出但数据未插入”的现象,是由几个叠加的逻辑错误导致的,逐点拆解如下:
- 最核心的逻辑错误:方法内直接覆盖传入的参数集合
拿到外部传入的category列表后,第一行代码就执行了category = new ArrayList<>();,直接把装有所有枚举值的非空列表替换成了空集合。后续for循环遍历的是这个新建的空列表,循环体完全不会执行——既不会做参数绑定,也不会触发SQL执行,整个流程无任何分支抛出异常,自然表现为程序正常结束但数据库无数据写入。 - 参数绑定逻辑完全失效
即便移除上面的集合覆盖代码,循环内的写法也存在错误:statement.setString(1, category.toString())绑定的是整个List集合的字符串输出,不是当前遍历的单个Category实例的名称- 循环内写的
category.add(categories)会在遍历非空集合时触发并发修改异常,直接导致流程中断
- 枚举类的字段赋值缺陷
你为Category枚举定义了两个重载构造器:一个接收int类型的分类编号,一个接收String类型的分类名称。但所有枚举常量初始化时,调用的都是接收int参数的构造器——给字符串名称字段赋值的构造器从未被触发,所有枚举实例的名称字段都是null,哪怕前面的执行逻辑跑通,写入数据库的NAME值也全是空值。 - 执行效率优化
当前循环内每遍历一个元素就单次执行一次SQL,频繁和数据库产生交互开销,数据量稍大时性能很差,可以配合JDBC批量执行能力优化。
修正后可正常运行的代码
修正后的addCategories方法
private ConnectionPool pool = ConnectionPool.getInstance(); @Override public void addCategories(List<Category> category) throws SQLException { // 删除覆盖传入集合的错误代码,直接复用外部传入的列表 Connection connection = pool.getConnection(); boolean originalAutoCommit = connection.getAutoCommit(); // 关闭自动提交,配合批量插入减少事务开销 connection.setAutoCommit(false); // 使用try-with-resources自动释放PreparedStatement资源 try (PreparedStatement statement = connection.prepareStatement( "insert into `couponsystem`.`categories` (NAME) VALUES (?)")) { for (Category singleCategory : category) { // 绑定当前单个分类的名称值,移除错误的集合toString逻辑 statement.setString(1, singleCategory.name()); // 将SQL加入批量执行队列,替代循环内单次executeUpdate statement.addBatch(); } // 一次性提交所有批量插入操作 statement.executeBatch(); connection.commit(); } catch (SQLException e) { // 出现异常时回滚未提交的事务,避免脏数据 if (connection != null) { connection.rollback(); } throw e; } finally { // 恢复连接原有的自动提交配置,避免放回连接池后影响其他业务使用 connection.setAutoCommit(originalAutoCommit); pool.restoreConnection(connection); } }
修正后的Category枚举类
public enum Category { // 枚举初始化时同时传入编号和名称,解决名称字段为null的问题 FOOD(1, "FOOD"), ELECTRICITY(2, "ELECTRICITY"), RESTAURANT(3, "RESTAURANT"), VACATION(4, "VACATION"), HOTEL(5, "HOTEL"); private final int catId; private final String catName; // 合并冗余的两个构造器,初始化时同时完成两个字段的赋值 Category(int catId, String catName) { this.catId = catId; this.catName = catName; } public int getIDX() { return catId; } public String getName() { return catName; } }
内容的提问来源于stack exchange,提问作者Daniel R
相关产品推荐
相关产品推荐

