https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-usagenotes-basic.html
程序访问数据库
通用的程序访问数据库的步骤
- Java 进程申请和 MySQL 服务器端建立 TCP 连接
- 成功建立 TCP 连接后,Java 进程将封装了 SQL 语句的网络包发送给 MySQL 服务器端
- MySQL 服务器端接收到网络包后,解析到网络包中的 SQL 语句
MySQL 服务器端将 SQL 语句的执行结果返回给 Java 进程
建立数据库连接的方式
Java 程序建立数据库连接的步骤
导入厂商实现的数据库驱动程序 (Driver)
- 实例化数据库驱动程序
- 提供建立数据库连接需要的数据(url、user、password)
尝试建立数据库连接
public static void main(String[] args) {
SpringApplication.run(CommunityApplication.class, args);
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
// 将数据库驱动程序加载到 JVM 虚拟机
Class.forName("com.mysql.cj.jdbc.Driver");
// 提供建立数据库连接需要的数据(url、user、password)
// 要连接的数据库的 URL
String url = "jdbc:mysql://localhost:3307/community?serverTimezone=UTC";
String user = "root";
String password = "root";
// 尝试建立数据库连接
connection = DriverManager.getConnection(url, user, password);
statement = connection.createStatement();
String sql = "select * from user;";
resultSet = statement.executeQuery(sql);
while (resultSet.next()) {
// 下标从 1 开始
System.out.println(resultSet.getInt(1));
}
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
} finally {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
resultSet = null;
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
statement = null;
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
connection = null;
}
}
DriverManager 原理说明
通过 Class.forName("com.mysql.cj.jdbc.Driver");
,将数据库驱动程序加载到 JVM 虚拟机时,
会执行 Drive 类的 static 包裹的静态代码块,静态代码块中创建了一个 Driver 实例,
并注册到 DriverManager 中,相当于将 Driver 实例交给 DriverManager 管理。
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
这样我们就可以在 DriverManager 中,通过不同的 url 获取不同的驱动,从而获取不同的连接了。
在 DriverManager.getConnection(url, user, password);
中,遍历所有已经注册到 DriverManager 中的 Driver 实例,以判断传入的 url 对应的数据库是哪个 Driver 管理。
// Worker method called by the public getConnection() methods.
private static Connection getConnection(
String url, java.util.Properties info, Class<?> caller) throws SQLException {
/*
* When callerCl is null, we should check the application's
* (which is invoking this class indirectly)
* classloader, so that the JDBC driver class outside rt.jar
* can be loaded from here.
*/
ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
synchronized(DriverManager.class) {
// synchronize loading of the correct classloader.
if (callerCL == null) {
callerCL = Thread.currentThread().getContextClassLoader();
}
}
if(url == null) {
throw new SQLException("The url cannot be null", "08001");
}
println("DriverManager.getConnection(\"" + url + "\")");
// Walk through the loaded registeredDrivers attempting to make a connection.
// Remember the first exception that gets raised so we can reraise it.
SQLException reason = null;
// 遍历所有已经注册到 DriverManager 中的 Driver 实例
for(DriverInfo aDriver : registeredDrivers) {
// If the caller does not have permission to load the driver then
// skip it.
if(isDriverAllowed(aDriver.driver, callerCL)) {
try {
println(" trying " + aDriver.driver.getClass().getName());
Connection con = aDriver.driver.connect(url, info);
if (con != null) {
// Success!
println("getConnection returning " + aDriver.driver.getClass().getName());
return (con);
}
} catch (SQLException ex) {
if (reason == null) {
reason = ex;
}
}
} else {
println(" skipping: " + aDriver.getClass().getName());
}
}
// if we got here nobody could connect.
if (reason != null) {
println("getConnection failed: " + reason);
throw reason;
}
println("getConnection: no suitable driver found for "+ url);
throw new SQLException("No suitable driver found for "+ url, "08001");
}
PreparedStatement
PreparedStatement 接口是 Statement 的子接口, PreparedStatement 可以进行预编译 SQL,而 Statement 不能。
public void testPreparedStatement() {
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
connection = dataSource.getConnection();
preparedStatement
= connection.prepareStatement("select `id` from `user` where `username` = ? ");
preparedStatement.setString(1, "admin");
// 结果集
resultSet = preparedStatement.executeQuery();
// 结果集的元数据,可以获取列的信息,比如: 列的类型、名称等
// Mybatis 底层就是通过这个元数据,利用反射技术进行 ORM(对象关系映射)
ResultSetMetaData metaData = resultSet.getMetaData();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
resultSet = null;
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
preparedStatement = null;
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
connection = null;
}
}
DataSource 接口
JDBC2.0 提供了 javax.sql.DataSource 接口。 DataSource 接口 负责建立与数据库的连接,当在应用程序中访问数据库时不必编写连接数据库的代码, 直接引用 DataSource 获取数据库的连接对象即可。 总而言之,DataSource 接口用于获取操作数据库的 Connection 对象。
DataSource 接口具体的实现由各个框架提供,比如:MyBatis、Druid、 C3P0。
数据库连接池
mysql-connector-java 与 MySQL 版本的对应关系
https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-versions.html
https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-versions.html