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
相关产品推荐
相关产品推荐

