JDBC工具类连接数据库时出现Utils.connection为空的错误求助
问题核心原因
你遇到的Cannot invoke "java.sql.Connection.prepareStatement(String)" because "Utils.connection" is null异常,本质是数据库连接初始化的时机晚于数据库操作执行的时机。
看你的代码执行顺序:
在Contacts的main方法中,是先执行new Contacts()触发构造函数(构造函数里直接调用loadContacts()执行数据库查询),之后才调用Utils.Connect()初始化连接。所以当loadContacts执行时,Utils.connection还未被赋值,自然抛出空指针异常。
分步修复方案
1. 调整连接初始化顺序
把Utils.Connect()放到创建Contacts实例之前,确保连接先初始化完成:
public static void main(String[] args) { // 先初始化数据库连接 Utils.Connect(); frame.setContentPane(new Contacts().Main); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); frame.setResizable(false); frame.setSize(500, 700); }
2. 修复listModel变量覆盖问题
你在Contacts构造函数里重新定义了listModel局部变量,会覆盖类成员变量,导致loadContacts里的listModel.clear()抛出空指针。改成直接初始化成员变量:
public Contacts() { // 不要重新定义变量,直接给成员变量赋值 listModel = new DefaultListModel<>(); list.setModel(listModel); loadContacts(); }
3. 修正SQL参数错误
你用String.valueOf(list)作为id参数完全不合理,JList的toString返回的不是你需要的id值。如果是要查询所有联系人,直接去掉WHERE条件:
Utils.preStmt = Utils.connection.prepareStatement("SELECT * FROM contactsdb"); // 无需设置参数,直接执行查询 Utils.rs = Utils.preStmt.executeQuery();
如果需要按id查询,要先获取选中项的有效id值(比如从列表项中解析):
if (!list.isSelectionEmpty()) { String selectedItem = (String) list.getSelectedValue(); // 假设列表项格式是"id 姓名 电话",解析出id String targetId = selectedItem.split(" ")[0]; Utils.preStmt = Utils.connection.prepareStatement("SELECT * FROM contactsdb WHERE id =?"); Utils.preStmt.setString(1, targetId); }
4. 重构Utils类(避免后续隐患)
你的Utils用静态成员存储Connection、PreparedStatement、ResultSet,在多线程环境下会出现资源冲突,还会导致连接泄漏。建议改成以下更安全的写法:
import java.sql.*; public class Utils { private static final String DB_URL = "jdbc:mysql://localhost:3306/testdb"; private static final String DB_USER = "root"; private static final String DB_PWD = ""; // 每次调用返回新的连接,避免静态成员冲突 public static Connection getConnection() throws SQLException { return DriverManager.getConnection(DB_URL, DB_USER, DB_PWD); } // 统一关闭资源,避免泄漏 public static void closeResources(Connection conn, PreparedStatement stmt, ResultSet rs) { try { if (rs != null) rs.close(); if (stmt != null) stmt.close(); if (conn != null) conn.close(); } catch (SQLException e) { e.printStackTrace(); } } }
之后在loadContacts中使用这个工具类:
public void loadContacts() { String name; String number; String address; listModel.clear(); Connection conn = null; PreparedStatement preStmt = null; ResultSet rs = null; try { conn = Utils.getConnection(); preStmt = conn.prepareStatement("SELECT * FROM contactsdb"); rs = preStmt.executeQuery(); while (rs.next()) { // 建议用列名而非索引,避免表结构变更导致错误 name = rs.getString("name"); number = rs.getString("number"); address = rs.getString("address"); listModel.addElement(name + " " + number + " " + address); } } catch (SQLException e) { e.printStackTrace(); } finally { // 确保资源一定会被关闭 Utils.closeResources(conn, preStmt, rs); } }
内容的提问来源于stack exchange,提问作者Landry Okoye

