You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Servlet中JDBC Connection对象返回Null问题排查求助

数据库连接在Servlet中返回Null的问题排查与解决

问题描述

开发Servlet时遇到数据库连接返回Null的问题,相同的数据库操作代码在其他类中可正常运行。已检查配置、加载JDBC驱动并在Tomcat上测试,但Servlet中的Connection对象始终为Null。

报错信息

Type Exception Report

Message 无法调用"java.sql.Connection.prepareStatement(String)",因为"connection"为null

Description 服务器遇到意外情况,无法完成请求。

Exception

java.lang.NullPointerException: 无法调用"java.sql.Connection.prepareStatement(String)",因为"connection"为null

相关代码文件

SingletonConnection.java

public class SingletonConnection {
    private static final String JDBC_URL = "jdbc:mysql://localhost:3306/CATALOGUE";
    private static final String USERNAME = "root";
    private static final String PASSWORD = "";
    private static Connection connection;
    static {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            connection = DriverManager.getConnection(JDBC_URL, USERNAME, PASSWORD);
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
    }
    public static Connection getConnection() {
        return connection;
    }
}

ProduitdaoImp.java

public class ProduitdaoImp implements IProduitdao {
    @Override
    public List<Produit> chercher(String mc) {
        Connection connection = SingletonConnection.getConnection();

        List<Produit> produits = new ArrayList<Produit>();
        try {
            PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM PRODUITS WHERE DESIGNATION LIKE ?");
            preparedStatement.setString(1, "%" + mc + "%");
            ResultSet rs = preparedStatement.executeQuery();
            while (rs.next()) {
                Produit p = new Produit();
                p.setId(rs.getInt("ID"));
                p.setPrix(rs.getDouble("PRIX"));
                p.setQuantite(rs.getLong("QUANTITE"));
                p.setDesignation(rs.getString("DESIGNATION"));
                produits.add(p);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return produits;
    }  
}

ControleurServlet.java

public class ControleurServlet extends HttpServlet {
    public IProduitdao iProduitdao;
    
    @Override
    public void init() throws ServletException {
        iProduitdao = new ProduitdaoImp();
    }
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String path = request.getServletPath();
        if (path.equals("/index.do")) {
            request.getRequestDispatcher("Produits.jsp").forward(request, response);
        } else if (path.equals("/chercher.do")) {
            String mot = request.getParameter("motcle");
            ProduitModel produitModel = new ProduitModel();
            produitModel.setMotCle(mot);
            List<Produit> produits = iProduitdao.chercher(mot);
            produitModel.setProduits(produits);
            request.setAttribute("model", produitModel);
            request.getRequestDispatcher("Produits.jsp").forward(request, response);
        }
    }
    
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }
}

Produits.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
    <title>Produits</title>
    <link rel="stylesheet" type="text/css" href="css/bootstrap.css">
</head>
<body>
<p></p>
<div>
    <div>
        <div> 商品搜索</div>
        <div></div>
        <form method="get" action="chercher.do">
        <label>关键词</label>
            <input type="text" name="motcle"/>
        <button type="submit">搜索</button>
        </form>
        <table>
            <tr>
            <th>ID</th><th>名称</th><th>价格</th><th>数量</th>
            </tr>
            <c:forEach items="${model.produits}" var="p">
                <tr>
                    <td>${p.id}</td>
                    <td>${p.designation}</td>
                    <td>${p.prix}</td>
                    <td>${p.quantite}</td>
                </tr>
            </c:forEach>
        </table>
    </div>
</div>
</body>
</html>

排查与解决方案

1. 修复单例连接的静默失败问题

SingletonConnection的静态代码块捕获异常后仅打印栈信息,未暴露初始化失败的问题,导致connection保持Null。修改静态块,抛出运行时异常明确报错:

static {
    try {
        Class.forName("com.mysql.cj.jdbc.Driver");
        connection = DriverManager.getConnection(JDBC_URL, USERNAME, PASSWORD);
    } catch (ClassNotFoundException | SQLException e) {
        throw new RuntimeException("数据库连接初始化失败", e);
    }
}

2. 检查JDBC驱动的类加载

确保mysql-connector-java.jar放置在项目的WEB-INF/lib目录下(或Tomcat的全局lib目录),避免Servlet容器无法加载驱动类导致初始化失败。

3. 验证数据库连接参数

  • 确认MySQL服务已启动,端口3306正常监听
  • 检查CATALOGUE数据库是否存在
  • 验证root用户密码是否正确(部分环境root默认有密码,并非空字符串)
  • 在JDBC_URL中添加时区参数避免时区错误:jdbc:mysql://localhost:3306/CATALOGUE?useSSL=false&serverTimezone=UTC

4. 增加连接有效性检查

单例连接可能因长时间闲置被数据库断开,在getConnection方法中检查连接状态,无效则重新创建:

public static Connection getConnection() {
    try {
        if (connection == null || connection.isClosed()) {
            connection = DriverManager.getConnection(JDBC_URL, USERNAME, PASSWORD);
        }
    } catch (SQLException e) {
        throw new RuntimeException("获取数据库连接失败", e);
    }
    return connection;
}

5. 增强DAO层的空指针防护

在ProduitdaoImp中先检查connection是否为Null,避免后续空指针,同时使用try-with-resources自动关闭资源:

@Override
public List<Produit> chercher(String mc) {
    Connection connection = SingletonConnection.getConnection();
    if (connection == null) {
        throw new RuntimeException("数据库连接未初始化");
    }
    List<Produit> produits = new ArrayList<>();
    try (PreparedStatement preparedStatement = connection.prepareStatement(
            "SELECT * FROM PRODUITS WHERE DESIGNATION LIKE ?")) {
        preparedStatement.setString(1, "%" + mc + "%");
        try (ResultSet rs = preparedStatement.executeQuery()) {
            while (rs.next()) {
                Produit p = new Produit();
                p.setId(rs.getInt("ID"));
                p.setPrix(rs.getDouble("PRIX"));
                p.setQuantite(rs.getLong("QUANTITE"));
                p.setDesignation(rs.getString("DESIGNATION"));
                produits.add(p);
            }
        }
    } catch (SQLException e) {
        throw new RuntimeException("查询商品失败", e);
    }
    return produits;
}

内容的提问来源于stack exchange,提问作者ussahimself

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 14:44:54