Servlet调用prepareStatement报错conn为null且init()未执行问题
问题根因
this.conn空指针、init()方法未执行的核心原因有两个:
- Servlet未被Tomcat正确注册,或重写init方法时违反Servlet生命周期规范,导致初始化逻辑根本没有触发
- 初始化阶段的异常被捕获后仅打印栈日志,没有向外抛出,Tomcat无法感知到Servlet初始化失败,仍正常把请求分发到未完成初始化的Servlet实例,最终在执行prepareStatement时触发空指针。
修复步骤
- 先确认Servlet已完成注册,未注册的类不会被Tomcat识别为Servlet,自然不会执行init、service等生命周期方法。两种注册方式选一个就行:
- 注解方式(Servlet 3.0及以上支持,配置简单):在RegisterUser类定义上方加
@WebServlet注解,指定访问路径:@WebServlet("/registerUser") public class RegisterUser extends GenericServlet { // 类内原有代码保持不变 } - web.xml配置方式:在项目的
WEB-INF/web.xml文件中添加如下配置:<servlet> <servlet-name>RegisterUser</servlet-name> <servlet-class>login_registration.RegisterUser</servlet-class> <!-- 加load-on-startup配置后,Tomcat启动时就会初始化Servlet,不用等第一次请求才触发init --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>RegisterUser</servlet-name> <url-pattern>/registerUser</url-pattern> </servlet-mapping>
- 注解方式(Servlet 3.0及以上支持,配置简单):在RegisterUser类定义上方加
- 修正init方法的写法,严格遵循Servlet规范。GenericServlet的init方法有两个重载,重写时不要破坏父类的初始化逻辑:
优先选无参init重写方案,不需要手动调用super,GenericServlet内部的带参init方法会自动调用这个无参方法,不会出现初始化流程断裂的问题:
如果要重写带@Override public void init() throws ServletException { try { Class.forName("oracle.jdbc.driver.OracleDriver"); conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "c##jdbc_practice", "Oracle123"); } catch (ClassNotFoundException | SQLException e) { // 初始化失败直接抛出ServletException,让Tomcat感知初始化异常,禁止吞掉异常只打日志 throw new ServletException("数据库连接初始化失败", e); } }ServletConfig参数的init方法,必须在方法第一行调用父类的初始化方法,否则会导致Servlet配置加载失败:@Override public void init(ServletConfig config) throws ServletException { super.init(config); // 这行必须保留,否则初始化流程断裂 // 后续数据库连接初始化逻辑和上述无参init中的代码一致 } - 修复service方法里的HTML语法错误,把写错的闭合标签
</hi改成</h1>,避免返回的页面渲染异常。 - 长期优化建议:不要把
Connection定义为Servlet的实例变量长期持有。Servlet是单例多线程模型,所有并发请求会共用同一个数据库连接,很容易出现请求数据错乱、连接意外断开后无法自动恢复的问题。后续请使用数据库连接池(如HikariCP、Druid)管理连接,每次请求处理时从连接池获取连接,用完立刻归还。
验证方式
改完代码后重新打包部署到Tomcat,第一次访问对应注册路径时,Tomcat会自动触发init方法完成数据库连接初始化,可以在init方法里临时加一行打印System.out.println("init执行完成,连接状态:" + (conn != null));,确认控制台打印连接为true后,再测试注册数据写入逻辑。
内容的提问来源于stack exchange,提问作者Sai Siddanth
相关产品推荐
相关产品推荐

