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)// 要连接的数据库的 URLString 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
