为何我的JSP场景仍需使用Class.forName加载MariaDB JDBC驱动?
根据官方文档说明,在Java 11、JavaEE 8搭配Gradle的环境中,无需调用Class.forName加载JDBC驱动。但在我的JSP场景中,如果不执行Class.forName("org.mariadb.jdbc.Driver"),就会触发HTTP 500错误,错误信息如下:
java.lang.RuntimeException: java.sql.SQLException: No suitable driver found for jdbc:mariadb://localhost:3306/mydb
添加该行代码后就能正常连接数据库。相关JSP代码如下:
<%@ page import="java.sql.Connection" %> <%@ page import="java.sql.DriverManager" %> <%@ page import="java.sql.SQLException" %> <%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %> <% Connection conn = null; Class.forName("org.mariadb.jdbc.Driver"); try { conn = DriverManager.getConnection("jdbc:mariadb://localhost:3306/mydb", "root", "1234"); } catch (SQLException e) { throw new RuntimeException(e); } conn.setAutoCommit(false); %>
原因分析
类加载器层级隔离
JSP页面由Web容器的JSP专属类加载器加载,而JDBC驱动的自动注册依赖META-INF/services/java.sql.Driver配置文件被系统类加载器或线程上下文类加载器读取。如果MariaDB驱动JAR包放在WEB-INF/lib下,会被Web应用类加载器加载——根据类加载器的双亲委派机制,系统类加载器(加载DriverManager的类加载器)无法看到子加载器加载的驱动类,自然无法通过自动注册机制发现它。DriverManager的加载限制
Java 6+的JDBC自动注册机制,要求驱动类的类加载器与DriverManager的类加载器处于同一层级或父层级。JSP场景中DriverManager由系统类加载器加载,驱动类由Web应用类加载器加载,两者不在同一加载层级,DriverManager无法通过服务发现找到驱动。显式调用Class.forName会触发驱动类初始化,让驱动类主动调用DriverManager.registerDriver()完成注册,绕过层级限制。Web容器扫描缺失
部分Web容器对JSP的类加载策略做了特殊隔离或优化,导致META-INF/services下的服务配置文件没有被正确扫描。显式加载驱动类可以直接跳过容器的扫描流程,强制完成驱动注册。
内容的提问来源于stack exchange,提问作者Moon

