https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-usagenotes-basic.html

程序是如何访问数据库的

程序访问数据库

通用的程序访问数据库的步骤

  1. Java 进程申请和 MySQL 服务器端建立 TCP 连接
  2. 成功建立 TCP 连接后,Java 进程将封装了 SQL 语句的网络包发送给 MySQL 服务器端
  3. MySQL 服务器端接收到网络包后,解析到网络包中的 SQL 语句
  4. MySQL 服务器端将 SQL 语句的执行结果返回给 Java 进程

    建立数据库连接的方式

    Java 程序建立数据库连接的步骤

  5. 导入厂商实现的数据库驱动程序 (Driver)

  6. 实例化数据库驱动程序
  7. 提供建立数据库连接需要的数据(url、user、password)
  8. 尝试建立数据库连接

    1. public static void main(String[] args) {
    2. SpringApplication.run(CommunityApplication.class, args);
    3. Connection connection = null;
    4. Statement statement = null;
    5. ResultSet resultSet = null;
    6. try {
    7. // 将数据库驱动程序加载到 JVM 虚拟机
    8. Class.forName("com.mysql.cj.jdbc.Driver");
    9. // 提供建立数据库连接需要的数据(url、user、password)
    10. // 要连接的数据库的 URL
    11. String url = "jdbc:mysql://localhost:3307/community?serverTimezone=UTC";
    12. String user = "root";
    13. String password = "root";
    14. // 尝试建立数据库连接
    15. connection = DriverManager.getConnection(url, user, password);
    16. statement = connection.createStatement();
    17. String sql = "select * from user;";
    18. resultSet = statement.executeQuery(sql);
    19. while (resultSet.next()) {
    20. // 下标从 1 开始
    21. System.out.println(resultSet.getInt(1));
    22. }
    23. } catch (SQLException e) {
    24. e.printStackTrace();
    25. } catch (ClassNotFoundException e1) {
    26. e1.printStackTrace();
    27. } finally {
    28. if (resultSet != null) {
    29. try {
    30. resultSet.close();
    31. } catch (SQLException e) {
    32. e.printStackTrace();
    33. }
    34. resultSet = null;
    35. }
    36. if (statement != null) {
    37. try {
    38. statement.close();
    39. } catch (SQLException e) {
    40. e.printStackTrace();
    41. }
    42. statement = null;
    43. }
    44. if (connection != null) {
    45. try {
    46. connection.close();
    47. } catch (SQLException e) {
    48. e.printStackTrace();
    49. }
    50. }
    51. connection = null;
    52. }
    53. }

DriverManager 原理说明
通过 Class.forName("com.mysql.cj.jdbc.Driver");,将数据库驱动程序加载到 JVM 虚拟机时,
会执行 Drive 类的 static 包裹的静态代码块,静态代码块中创建了一个 Driver 实例,
并注册到 DriverManager 中,相当于将 Driver 实例交给 DriverManager 管理。

  1. static {
  2. try {
  3. java.sql.DriverManager.registerDriver(new Driver());
  4. } catch (SQLException E) {
  5. throw new RuntimeException("Can't register driver!");
  6. }
  7. }

这样我们就可以在 DriverManager 中,通过不同的 url 获取不同的驱动,从而获取不同的连接了。

DriverManager.getConnection(url, user, password); 中,遍历所有已经注册到 DriverManager 中的 Driver 实例,以判断传入的 url 对应的数据库是哪个 Driver 管理。

  1. // Worker method called by the public getConnection() methods.
  2. private static Connection getConnection(
  3. String url, java.util.Properties info, Class<?> caller) throws SQLException {
  4. /*
  5. * When callerCl is null, we should check the application's
  6. * (which is invoking this class indirectly)
  7. * classloader, so that the JDBC driver class outside rt.jar
  8. * can be loaded from here.
  9. */
  10. ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
  11. synchronized(DriverManager.class) {
  12. // synchronize loading of the correct classloader.
  13. if (callerCL == null) {
  14. callerCL = Thread.currentThread().getContextClassLoader();
  15. }
  16. }
  17. if(url == null) {
  18. throw new SQLException("The url cannot be null", "08001");
  19. }
  20. println("DriverManager.getConnection(\"" + url + "\")");
  21. // Walk through the loaded registeredDrivers attempting to make a connection.
  22. // Remember the first exception that gets raised so we can reraise it.
  23. SQLException reason = null;
  24. // 遍历所有已经注册到 DriverManager 中的 Driver 实例
  25. for(DriverInfo aDriver : registeredDrivers) {
  26. // If the caller does not have permission to load the driver then
  27. // skip it.
  28. if(isDriverAllowed(aDriver.driver, callerCL)) {
  29. try {
  30. println(" trying " + aDriver.driver.getClass().getName());
  31. Connection con = aDriver.driver.connect(url, info);
  32. if (con != null) {
  33. // Success!
  34. println("getConnection returning " + aDriver.driver.getClass().getName());
  35. return (con);
  36. }
  37. } catch (SQLException ex) {
  38. if (reason == null) {
  39. reason = ex;
  40. }
  41. }
  42. } else {
  43. println(" skipping: " + aDriver.getClass().getName());
  44. }
  45. }
  46. // if we got here nobody could connect.
  47. if (reason != null) {
  48. println("getConnection failed: " + reason);
  49. throw reason;
  50. }
  51. println("getConnection: no suitable driver found for "+ url);
  52. throw new SQLException("No suitable driver found for "+ url, "08001");
  53. }

PreparedStatement

PreparedStatement 接口是 Statement 的子接口, PreparedStatement 可以进行预编译 SQL,而 Statement 不能。

  1. public void testPreparedStatement() {
  2. Connection connection = null;
  3. PreparedStatement preparedStatement = null;
  4. ResultSet resultSet = null;
  5. try {
  6. connection = dataSource.getConnection();
  7. preparedStatement
  8. = connection.prepareStatement("select `id` from `user` where `username` = ? ");
  9. preparedStatement.setString(1, "admin");
  10. // 结果集
  11. resultSet = preparedStatement.executeQuery();
  12. // 结果集的元数据,可以获取列的信息,比如: 列的类型、名称等
  13. // Mybatis 底层就是通过这个元数据,利用反射技术进行 ORM(对象关系映射)
  14. ResultSetMetaData metaData = resultSet.getMetaData();
  15. } catch (SQLException e) {
  16. e.printStackTrace();
  17. } finally {
  18. try {
  19. resultSet.close();
  20. } catch (SQLException e) {
  21. e.printStackTrace();
  22. }
  23. resultSet = null;
  24. try {
  25. preparedStatement.close();
  26. } catch (SQLException e) {
  27. e.printStackTrace();
  28. }
  29. preparedStatement = null;
  30. try {
  31. connection.close();
  32. } catch (SQLException e) {
  33. e.printStackTrace();
  34. }
  35. connection = null;
  36. }
  37. }

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