0x01 环境搭配
如果还不会搭建jsp环境的可以按照下面的文章跟着搭建
Mac版IDEA创建maven web项目-详细过程: https://www.yuque.com/pmiaowu/gpy1q8/npv0fr
0x02 导入数据库驱动
0x02.1 maven自动添加
打开: https://mvnrepository.com/
搜索: MySQL
点进去: https://mvnrepository.com/artifact/mysql/mysql-connector-java
我这里选择5.1.41
打开: https://mvnrepository.com/artifact/mysql/mysql-connector-java/5.1.41
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.41</version>
</dependency>
0x02.2 手动导入
首先介绍如何手动下载jar包
打开: https://mvnrepository.com/artifact/mysql/mysql-connector-java/5.1.41
下载地址: https://repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.41/mysql-connector-java-5.1.41.jar
0x03 JDBC链接数据库
// 使用例子
# 目录结构
├── src
│ └── main
│ └── webapp
│ └── com
│ └── Servlet
│ ├── ...
│ └── DBTest.java
│ └── WEB-INF
│ └── web.xml
│ └── index.jsp
package com.Servlet;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.*;
@WebServlet("/DBTest")
public class DBTest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
String DRIVER_NAME = "com.mysql.jdbc.Driver";
// jdbc:mysql://[mysql地址]:[mysql端口]/[要连接的数据库名]
String URL = "jdbc:mysql://192.168.24.145:3306/mysql";
String USER_NAME = "root";
String PASSWORD = "123456";
Connection connection = null;
try {
//加载mysql的驱动类
Class.forName(DRIVER_NAME);
//获取数据库连接
connection = DriverManager.getConnection(URL, USER_NAME, PASSWORD);
//mysql查询语句
String sql = "SELECT * FROM `user`";
PreparedStatement prst = connection.prepareStatement(sql);
//结果集
ResultSet rs = prst.executeQuery();
while (rs.next()) {
response.getWriter().println(" ");
response.getWriter().println("用户名:" + rs.getString("User")+" "+"密码:" + rs.getString("Password"));
}
rs.close();
prst.close();
} catch (Exception e) {
e.printStackTrace();
}finally {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
// 执行该文件
// 例如: http://127.0.0.1:8081/mavenJspTest_war/DBTest
0x04 问题小结
在开始使用的时候,我一直不理解
为什么第一步需要Class.forName("com.mysql.jdbc.Driver");
不可以删除么?于是删除以后,我发现还是可以正常连接数据库,这让我更加迷惑了
0x04.1 为什么需要Class.forName?
经过查看源码终于理解了
首先我们要知道Class.forName("xxxx")
的功能: 除了将类的.class文件加载到jvm
中之外,还会对类进行解释,执行类中的static
块
那么Class.forName("com.mysql.jdbc.Driver");
干了什么?
先进入com.mysql.jdbc.Driver
类
看到这里大致就明白了,也就是说Class.forName("com.mysql.jdbc.Driver");
实际上会触发类加载com.mysql.jdbc.Driver
类将会被初始化,并且执行类中的static
块
实际上这一步就是利用了Java反射+类加载机制往DriverManager
中注册了驱动包
0x04.2 删除了Class.forName为什么还可以?
为什么我不加Class.forName("com.mysql.jdbc.Driver");
一样可以正常连接数据库?
实际上这里利用了Java的一大特性: Java SPI(Service Provider Interface)
DriverManager
在初始化时,会调用java.util.ServiceLoader
类提供的SPI机制
然后Java自动扫描jar包中的META-INF/services目录下的文件,并且还会自动的Class.forName
文件中定义的类
这就是为什么不需要Class.forName也能够成功连接数据库的原因了
怎么判断有没有用SPI?可以考察如下示例
方法一: 查看包的结构,Mysql驱动包示例:
如上图, META-INF/services下面能看到长的很像类的完全限定名,就八九不离十了。
方法二: 通过查看源码
例如: 查看DriverManager
类
查找java.util.ServiceLoader.load
看看是否有调用
0x05 课外知识补充
如果想反射某个类又不想初始化类方法可以么?
当然可以,解决方案如下:
- 使用
Class.forName("xxxx", false, loader)
方法 - 使用
ClassLoader.loadClass("xxxx")
0x06 小结
在实际的项目中,通常不会使用原生的JDBC
的DriverManager
去连接数据库
而是使用javax.sql.DataSource(数据源)
来代替DriverManager
因此本文学习如何使用原生来操作数据库,让自己脑子留个底子即可
有关javax.sql.DataSource(数据源)
使用的问题,我们后面在一起学习